Friday, January 27, 2017

Building an IBM QRadar Console in AWS (For version 7.2.7) - Part 2

This post basically is based on a comment from the previous post. Once again,
Special thanks to Naomi Rampersad for this entry.



The IBM website does not identify any difference in the prerequisites for whether you are configuring a Console, EP/EC or FP/FC. In fact they simply state the build for “Configuring a QRadar host on Amazon Web Service”. The document posted is an actual build of a Console and contains an imported console configuration.

With that said and as you know, dependent of how many EPS or FPM you are supporting, the compute and disk space components matter. Please see below.

 




































AWS has different instance types (T2,M4, M3,C4,C3,X1,R4,R3,etc). The M4 instances are the latest generation of general purpose instances providing a balance of compute, memory, and network resources, and it is a good choice for many applications. We typically stick to the M4 series for our EP and FP builds. You can use m4.2xlarge or m4.4xlarge or go higher and then provision your storage accordingly.




 























Hope this helps!

Friday, January 13, 2017

Building an IBM QRadar Console in AWS (For version 7.2.7)

Special thanks to Naomi Rampersad for this entry.

Building an IBM QRadar Console in AWS
(For version 7.2.7)
1.    Configure a key pair on AWS.
2.    Create an Amazon EC2 instance that meets the following requirements:
Image = RHEL-6.7_HVM_Beta-20150430-x86_64-1-Hourly2-GP2, found in Community AMIs
Instance type = m4.2xlarge
Storage    Three disks:
1 x 250 GB volume
2 x 200 GB volumes
Security Group = Your IP addresses from the list, with ports 22 and 443 open.
Create an elastic IP


The AWS instance key is required to log in to the instance with SSH.
XFS is not supported on the RedHat Enterprise Linux (RHEL) v6.7 loads that are provided by AWS. Use ext4.
Important: High availability (HA) is not supported on AWS QRadar installations.

1.    To log in to the AWS instance by using the key pair that you created when you configured the instance, type the following command or use Putty.
ssh -I <your_key>.pem ec2-user@<public_IP_address>
2.    Enter the root shell of the AWS instance by using the following command:
sudo su -
3.    Determine the device that you want to configure:
Type the lsblk command to list device details.
# lsblk
NAME    MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
xvda    202:0    0  250G  0 disk
└─xvda1 202:1    0  250G  0 part /
xvdb    202:16   0    200G  0 disk
xvdc    202:32   0    200G  0 disk 
Find the device that has no partitions and has the required storage.
After you find the block devices, export the device name and device data as environment variables for use in subsequent steps. For the preceding example, you type the following commands:
export device_name=/dev/xvdc
export device_data=/dev/xvdb
4.    To create the partition type for the disk (label), type the following commands:
parted -a optimal --script ${device_name} -- mklabel gpt
parted -a optimal --script ${device_data} -- mklabel gpt
5.    To create these partitions on the device, type the following commands:
Note: The following allocations are examples.
parted -a optimal --script ${device_name} -- mkpart swap 0% 30%
parted -a optimal --script ${device_name} -- mkpart ext4 30% 60%
parted -a optimal --script ${device_name} -- mkpart ext4 60% 100%
parted -a optimal --script ${device_data} -- mkpart ext4 0% 80%
parted -a optimal --script ${device_data} -- mkpart ext4 80% 100%
6.    To create the following file systems on the partitioned device, type the following commands:
mkswap -L swap1 ${device_name}1
mkfs.ext4 ${device_name}2
mkfs.ext4 ${device_name}3
mkfs.ext4 ${device_data}1
mkfs.ext4 ${device_data}2
7.    Label the partitions with the following names:
e2label ${device_name}2 /var/log
e2label ${device_name}3 /store/tmp
e2label ${device_data}2 /store/transient
e2label ${device_data}1 /store
8.    In the /etc/fstab file, comment out the /dev/<device_name> /mnt, or /dev/<device_data> /mnt lines if they are present.
9.    Type the following commands to add the required entries to /etc/fstab file:
eval `blkid -t LABEL=/store -o export` ; echo UUID=$UUID $LABEL $TYPE defaults,noatime 1 1 >> /etc/fstab
eval `blkid -t LABEL=/store/transient -o export` ; echo UUID=$UUID /store/transient $TYPE defaults,noatime 1 1 >> /etc/fstab
eval `blkid -t LABEL=/var/log -o export` ; echo UUID=$UUID $LABEL $TYPE defaults,noatime 1 1 >> /etc/fstab
eval `blkid -t LABEL=/store/tmp -o export` ; echo UUID=$UUID /store/tmp $TYPE defaults,noatime 1 1 >> /etc/fstab
echo "${device_name}1 swap swap defaults 0 0" >> /etc/fstab
10.    To create and mount the /store directory, type the following commands:
mkdir /store
mount /store
mkdir /store/tmp
mount /store/tmp
mkdir /store/transient
mount /store/transient
cd /var; mv log oldlog; mkdir log; mount /var/log; mv oldlog/* log
11.    To enable the swap between devices, type the following command:
swapon -a
12.    Confirm that the /etc/sysconfig/i18n line contains the following string, including the quotation marks:
LANG="en_US.UTF-8"
13.    To copy the ISO image to the device, type the following command or use WinSCP:
scp -i <key.pem qradar.iso> ec2-user@<Public_DNS>:qradar.iso
Important: Use SQ_SIEM_SWO7.2.7RHELML.iso image (Red Hat Linux version only)
14.    To mount the ISO image, type the following commands at the root directory:
mkdir /media/cdrom
mount -o loop /home/ec2-user/qradar.iso /media/cdrom
15.    Configure missing dependencies by using the following commands:
yum  install -y libxml2 libxml2.i686 audit-libs audit-libs.i686 glibc glibc.i686 device-mapper-multipath zlib zlib.i686 libcom_err libcom_err.i686 nspr nspr.i686 nss nss.i686 nss-util nss-util.i686 krb5-libs krb5-libs.i686 keyutils-libs keyutils-libs.i686 openssl   openssl.i686 httpd-tools httpd-devel httpd mod_ssl keyutils keyutils.i686 keyutils-libs keyutils-libs.i686 openldap openldap.i686 openldap-clients cyrus-sasl-lib cyrus-sasl-lib.i686 pam pam.i686 libgcc libgcc.i686 elfutils-libelf  elfutils-libelf.i686 libstdc++   libstdc++.i686

yum remove php.x86_64 php-cli.x86_64 php-common.x86_64 php-devel.x86_64 php-imap.x86_64 samba-common samba-winbind-clients samba-client samba-winbind httpd httpd-tools mod_ssl

sed -i -e "s/plugins=1/plugins=0/" /etc/yum.conf
16.    To start the setup program, type the following command:
/media/cdrom/setup
17.    Type Y when prompted to accept an installation on unsupported hardware.
18.    Follow the prompts and complete the QRadar installation wizard.

Restore a Configuration to the AWS Built IBM QRadar Console
(The IP address is different)
1.    Ensure the version and patch level is the same.
2.    Take an On Demand Backup on the original Console.
3.    Using SCP, copy the configuration backup file to /store/backupHost/inbound of the new Console.
4.    Ensure the hostname on the AWS Console is the same as the original is the same by using qchange_netsetup.
5.    Log in to the AWS QRadar Console as an administrator.
6.    Click the Admin tab and select the Backup and Recovery icon.
7.    Select the configuration backup you copied to the Console and click Restore.
8.    From the restore options list, select the Select All Configuration Items check box.
9.    From the restore options list, select the Select All Data Items check box.
10.    Click Restore to start the configuration restore process.
11.    From the Admin tab, click the Deploy Changes icon.
12.    Verify that event or flow sources that were reporting to the original host are being processed in the QRadar user interface.

Customized In-house Training vs Market Training - Gaining the most of the limited budget

Training budgets are continuing to shrink but training needs continue to grow while the cost of training increases and technology vendors continue to produce new tools and products. Thus to ensure these tools and products are being fully maximize so as to achieve a full return on investment (ROI), the users of these tools need to be properly trained to use them. As a result, steps need to be taken to ensure all human resources are continuing to develop their skills. The solution lies in the fact that the training that is provided to an entry level is not the same training that you can or should provide to a "season" veteran. This means that, we can balance out the budget by sending those more seasoned resources for external training, while developing training sessions to grow the "rookies" in house.

How do we do this? From a simple perspective ...
... for starters, you are better off working with the rookies to better perform the tasks the do on a daily basis. Once they are comfortable with understanding the basics of what they do and learn to expand beyond their current responsibilities, then we can look at getting them to understand the real "internals". After a barrage of different internal training you may then get to the point where you believed the rookies may have out grown the home grown training. At this point consideration should be given to sending them to external training to broaden the knowledge.

Considering the Cyber Security perspectives and investigations, one can begin by teaching the rookies how to ensure they are addressing the basics. The basics being the "What", "When", "Where" if possible "How" and "Why" it happened. Answering the "Why" would be the most difficult if you are looking at it from an attackers perspective. However, you can also answer "Why" from your organization's perspective. An example of why from the organizations perspective may be, because we were unable to patch as a result of being able to take the device offline for a reboot. Thus while we installed the patch it was not fully applied. Business risks tolerance will dictate a lot of not only what we do but how we do it.

Another part of the puzzle that rookies would need to be aware of is the importance of timelines, as timelines help to answer the when. The when is extremely important as it helps to understand the duration of an intrusion or the "detection deficit" as stated by Verizon. The when starts with the first event which is seen as part of this incident to the last event recorded. This put things into perspective and add clarity.

My belief is this compromise of sending seasoned veterans on external training while developing the rookies in house, allows everybody to grow on a scale which best suit there learning ability. This also allows the training budget to be used more efficiently as you would not be sending individuals on training because there is a training budget to be utilized. This also gives the more seasoned veterans the opportunity to coach and or lead the rookies as for this to work, someone with the experience have to conduct the training.

What's your thoughts on gaining the most from the limited budget when it comes to training.

Monday, January 2, 2017

Brute Forcing Web Authentication - Detection

In the previous post, we looked at performing a brute force attack against authentication. So let's take a second to see how this can be detected.

The reality is, this can be either easy or difficult to detect, based on your environment's configuration. If your environment has no logging enabled, then you should stop reading, as this post will do you no good. However, even for those environments that have logging enabled, they may only be logging successful or failed attempts and not both. If you really want to benefit from this post, then your environment should be logging both successful and failed attempts. Let's look at the events from the previous post to get a better understanding of why.

Before moving on, it is important to note that these authentication requests are being made via a "POST" method, as a result you should not expect on a regular day to see these entries in your web server logs. Below shows an example of logs from the web server:

-------------------

10.0.0.1 - - [05/Nov/2016:12:56:42 -0500] "POST /mut/index.php?page=login.php HTTP/1.1" 200 53225 "http://10.0.0.101/mut/index.php?page=login.php&popUpNotificationCode=LOU1" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:49.0) Gecko/20100101 Firefox/49.0"

10.0.0.1 - - [05/Nov/2016:12:56:42 -0500] "POST /mut/index.php?page=login.php HTTP/1.1" 200 53225 "http://10.0.0.101/mut/index.php?page=login.php&popUpNotificationCode=LOU1" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:49.0) Gecko/20100101 Firefox/49.0"

10.0.0.1 - - [05/Nov/2016:12:56:43 -0500] "POST /mut/index.php?page=login.php HTTP/1.1" 200 53225 "http://10.0.0.101/mut/index.php?page=login.php&popUpNotificationCode=LOU1" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:49.0) Gecko/20100101 Firefox/49.0

10.0.0.1 - - [05/Nov/2016:12:56:44 -0500] "POST /mut/index.php?page=login.php HTTP/1.1" 200 53225 "http://10.0.0.101/mut/index.php?page=login.php&popUpNotificationCode=LOU1" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:49.0) Gecko/20100101 Firefox/49.0"

10.0.0.1 - - [05/Nov/2016:12:56:45 -0500] "POST /mut/index.php?page=login.php HTTP/1.1" 200 53225 "http://10.0.0.101/mut/index.php?page=login.php&popUpNotificationCode=LOU1" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:49.0) Gecko/20100101 Firefox/49.0"

-------------------

So if information is not in the web server logs, where are we getting it from? Well in this case we have to get it from the authentication system or some other system that allows us to retrieve those logs. From our perspective we will look at the logs from Mutillidae's system. Below is a snapshot.



From the above we see an example of a username not existing. Unless an attacker has successfully enumerated all the usernames within your environment, there will be occasions that you will see this as part of a brute force attempt. Looking at the time, we see in come cases the time is practically the same down to the second.

Let's perform some additional analysis on the full log.

Total unique source IPs attacking us?

sansforensics@securitynik:~$ cat mutillidae-logs.txt | cut --fields 1 | sort | uniq --count | sort --numeric --reverse | more



From the above it looks like there were 188 attempts from one source IP. This should be an immediate cause for concern.

What type of computer is the person attacking us from?

sansforensics@securitynik:~$ cat mutillidae-logs.txt | cut --fields 3 | sort | uniq --count | sort --numeric --reverse | more


From the above we can conclude that all of these attacks came from a system running Windows 10 and the user is running Firefox. Note, we are trying to draw our conclusions based on the "User-Agent" string. However, this value can be easily forged. However, let's assume it is not.

Learning a bit more about the access attempts.

sansforensics@securitynik:~$ cat mutillidae-logs.txt | cut --fields 4 | sort | uniq --count | sort --numeric --reverse | more



From above we get a better insight into to what transpired.

Let's draw some conclusions.
- There were 62 attempts (from various users, etc) to access "login.php"
- User "securitynik" attempted to authenticate 14 different times. More than likely with different passwords. However, the account "securitynik" does not exist.
- Similarly user "sa", "nik", "guest" and "tes" do not exist. There were 11 failed attempts for these accounts.
- It also looks like user "admin" had "10" failed attempts.
- "admin" also had 3 successful logins

Let's take a final look at what transpired with "admin"

Looking at the date and times these access attempts were made we see the following.

sansforensics@securitynik:~$ cat mutillidae-logs.txt | grep --perl-regexp "User\sadmin" | awk --field-separator " " '{ print $17 " " $18 }'


We see that these attempts were made on November 5, 2016 between 12:56:40 and 13:51:54. Looking at the information we can draw some possible conclusions. It looks like there was one activity that lasted from 12:56:40 to 12:58:29 for a duration of 1 minute+. Another attempt was seen at 13:40:05 and another at 13:51:54.

Looking for the successful attempt

sansforensics@securitynik:~$ cat mutillidae-logs.txt | grep admin | grep Succeeded | awk --field-separator " " '{ print $12 " -> " $13 " -> " $17 " -> " $19 " " $20 }'



So  what can we do to help make this a bit more difficult for the potential attacker?
- For starters we should have a lockout policy. This allows the targeted account to be placed in a "disabled" state after a certain amount of failed tries and for a specific period. This is not bulletproof but can definitely slow down your attackers.
- Ensure you are logging both failed and successful authentication attempts. Being able to detect the reconnaissance is just as important as detecting the successful authentication attempt.

Good luck with your environment's logging. See my "building a forensically capable network infrastructure" for more guidance.

Brute Forcing Web Authentication - OWASP Mutillidae II & Burp Suite

Authentication is one of those mechanisms which is probably targeted more than anything else. Obviously the reason for this is understandable, as in most cases we have to authenticate to be able to complete a task. Be it we are authenticating against our computer, phones or an application, authentication is essential to what we do.

Since this is probably one of the most attacked mechanisms, we should know not only how the attacks are done but also how we can detect such attacks.

For this let's leverage "OWASP Mutillidae II". Specifically, we will leverage its "OWASP 2013 -> A2 Broken Authentication and Session Management -> Authentication Bypass -> Via Brute Force -> Login"


Figure 1: Mutillidae Login page from menu.

The above produces the following login page

Figure 2: Mutillidae Login page.

Let's now load up Burpsuite as we will need to intercept this traffic to be able to manipulate the authentication process.

Note we need to configure our browser to use the proxy. The image below is for FireFox's proxy configuration which is found under  "options -> advanced -> network".


Figure 3: Firefox proxy configuration.

Next we configure Burp Suite to listen (this is on by default) when Burpsuite is loaded.

Figure 4: Burp Suite Proxy intercept on.

Now that we have our browser configured to use our proxy and we have our proxy listening, let's go ahead and make the request from the login page. At this point the objective is to use any credentials, just to generate some traffic so that we can review it in the proxy.


Figure 5: Sample login

Once we click login, we see that data being intercepted by the proxy. This is where we will spend the rest of our time .... for now ...


Figure 6: Burp Suite intercept results

Next let's send this capture data to Burp Intruder.
Figure 7: Sending to Burp Intruder

Looking at Burp Intruder's "Position" tab

By default Intruder will highlight the fields which we can use as variables. What we will do is double click the ones we don't want and click "clear" from the buttons on the right. In the end we will be left with only two variables that we will use. These will be "username" and password. At this point the values in these fields are "securitynik" for username and "SomePassword" for the password field.

For the "Attack type" we will select "cluster bomb”


Figure 8: Results from Proxy Position tab

Stepping back a little ...

I created two files. the first consists of some usernames and the other some passwords:
"username-wordlist.txt"
nik
securitynik
admin
guest
sa

"password-wordlist.txt"
password
<blank> # This is just an empty password
admin
letmein
12345
adminpass

The above two files will be used in the "Payload" tab.

Let's select "Payload Set" "1". For this we will use a "Payload Type" of "Runtime file". Here we select our "username-wordlist.txt" file.

Figure 9: Burp Payload 1 (username) configuration

Let's set our 2nd payload. For this we will use our "password-wordlist.txt" file for the runtime file.

Figure 10: Burp Payload 2 (passwords) configuration

Once completed, let's "Start Attack". This will bring up
Figure 11: Results from password attack

As  we can see almost all of these attempts have a "status" of "200" and "Length" "53449". However, the anomaly lies in the "Status" code of "302" and a "Length" of 436. Since this is one that is different and has a Payload 1 (username) of "admin" and Payload 2 (password) of "adminpass" then we can assume this is probably the credentials that will work for us.

The request which was actually sent looks like:

Figure 12: Admin login successful
We  see our credentials were sent as part of a "POST" method

Let's look at the response for this request

Figure 13: Admin login successful. Response from server.

If  we look at the above image and contrast it with some of the other attempts, we see that this response has an "Expires" header with a value of "Thu, 19 Nov 1981 08:52:00 GMT", a "Set-Cookie" header with "username=admin" another "Set-Cookie" header with  "uid=1" and a "Location" of "index.php?popUpNotificationCode=AU1"

Let's now use the "admin" username and "adminpass" password to authenticate.


Figure 14: Testing the successful credential


Figure 15: Login successful


So  that's it for this post. In the next post let's look at how we can detect this type of activity.

Reference:
Mutillidae
Burpsuite
https://support.portswigger.net/customer/portal/articles/1964020-using-burp-to-brute-force-a-login-page
https://portswigger.net/burp/help/intruder_using.html
https://portswigger.net/burp/help/intruder_payloads_types.html
https://support.portswigger.net/customer/portal/articles/1783129-configuring-a-burp-intruder-attack
https://portswigger.net/burp/help/intruder_positions.html

Format String Vulnerability–Overwriting Memory

Continuing with the format string vulnerability, we previously looked at information leakage, this time let’s take a look at overwriting memory. With this vulnerability one can potentially replace permissions or may even cause a program to perform some other action on its behalf.

Let’s look at the code:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/*
 * fmtstr_overwrite.c
 * This code is from the original paper written by Tim Newsham
 * I'm just reusing it here for demonstrating purposes
 * original document can be found at: http://forum.ouah.org/FormatString.PDF
 *
 * check out my blog at http://securitynik.blogspot.com to learn more
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char **argv)
  {
    char buf[512];
    int x;
    
    if (argc != 2)
      exit(1);

    x = 1;
    snprintf(buf, sizeof buf, argv[1] );
    buf[sizeof buf -1] = 0;
    printf("buffer (%d) : %s\n",    strlen(buf), buf);
    printf(" x is %d/%#x (@ %p)\n", x, x, &x);
    return 0;

  }


Let’s go ahead and compile this program.




Once compiled, let’s run our program to see what we get. In running it, let’s provide the input of “Hey SecurityNik”


Figure 1: Program run and x is 1.

Above shows we ran the program and it showed us the size of our buffer is 15, which is basically the string “Hey SecurityNik”. We also know that “x” is 1 in decimal (1/0x1) and 0x1 in hex and can be found at memory address “0xffffd1b0”.

What we would like to change here is the value of “x” based on its memory location. To do that let’s leverage “perl” along with the “%d” and “%n” format specifiers. The “%d” specifies a decimal integer while the "%n" format returns the number of characters that should have been output.

What we will do now is use the following:
perl -e 'system "./fmtstr_overwrite.exe", "\xb0\xd1\xff\xff%d%n"'

This will overwrite the memory location with the value 5. Why 5? Look at it this way, we are giving the 8 hex characters “\xb0\xd1\xff\xff” which would equate to 4 ASCII characters (whether printable or not is not our concern at this time). Then the “%d” would be another input. So at this point we have 5. You may be wonder why not add one for “%n”. Well as stated above, “%n” prints the number of characters that should have been outputted. As a result, what “%n” will do is print the 5 characters that preceded it. Let’s look at this now in practice.


Figure 2: X is now 5.

As can be seen in figure 2, we have now overwritten the value of “x” to make it 5. If we wanted we could have made that number something else. Let’s say 504.

Figure 3: X is now 504.

As show in figure 3, we were able to change X’s value at memory address “0xffffd1b0” to 504.

While these examples may seem trivial, consider the case where a program requires a user with a certain numeric value to be the one who does administrative tasks. If someone is able to overwrite this variable with that specific value, she may be able to perform administrative actions. You may also be able to overwrite an executed program or even the return pointer.

OK! That’s it!!

References:
Tim Newsham - Guardent, Inc. - Format String Attacks
Syracuse University Lecture Notes – Format String Vulnerability
Stanford - scut / team teso – Exploiting Format String Vulnerabilities
Saif El-Sherei - Format String Exploitation - Tutorial
Format String Vulnerability I & II
Paul Haas - Advanced Format String Attacks
Stonybrook – Format String Attacks
Wei Wang - Format String Vulnerability
Format String Vulnerabilities
Blind Format String Attacks
SP&E – Buffer Overflow and Format String Overflow Vulnerabilities
USENIX: FormatGuard: Automatic Protection From printf  Format String Vulnerabilities
Yan Huang - Heap Overflows and Double-Free
Lok Kwong Yan - CS392/681 – Polytechnic University - An Introduction to Buffer Overflows and Format String Vulnerabilities
Format string exploitation on windows Using Immunity Debugger / Python
Andreas Thuemmel - Analysis of Format String Bugs

Sunday, January 1, 2017

Format String Vulnerability – Information Leakage

Format string vulnerability is one of those bugs which you may not even recognize that you are actually introducing a vulnerability by doing things “the easy way”. While I’m not a programmer by profession, I have made the mistake in code I’ve developed. Realistically compiling and running the program in most cases works just as well as if you were to do it the “correct way”.

While this post focuses on information leakage as a result of format string vulnerability and the other on overwriting memory, there are more that could be done to a program such as crashing a program.

Let’s start off with the code.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/*
 * fmtstr_info_leak.c
 * Sample code demonstrating Format String information leakage
 * Author: Nik Alleyne < nikalleyne at gmail dot com >
 * blog: http://securitynik.blogspot.com
 * Date: 2017-01-01
 */

#include <stdio.h>

int main( int argc, char **argv )
  {
    // Putting some stuff on the stack
    char *str1 = " Pop pop, it's show time (Show time) \n";
    char *str2 = " Guess who's back again? \n";

    // Correct way to code 
    //printf("%s", argv[1]);

    // Wrong way to code - introduces vulnerability
    printf(argv[1]);
    return 0;
  }



Let’s now compile this code using “gcc -ggdb -m32 -mpreferred-stack-boundary=2 -fno-stack-protector fmtstr_info_leak.c -o fmtstr_info_leak.exe”



Figure 1: code being compiled. Note the compiler’s warning about “printf”

Now that we’ve compiled the code, let’s run it.

Figure 2: Code run and user input echoed.

Looking at figure 2, we see that when the word “SecurityNik” was entered this was echoed back to the user. So far so good, no harm done. However, what about if we were to enter “%s %s” as the input, what would happen? Let’s find out.

Figure 3: Information leaked

What just happen there?
Well what we did was to print the next two values on the stack. These values being 2 strings. “printf” expected its arguments to be represented via one or more format specifiers. As a result when we used “%s %s” specifiers the next two values on the stack were picked up. Look at it this way, if we had “%s” as in only one “%s”, we would have printed the next value on the stack.

Looking deeper
To get a better understanding of this let’s take a look at what the stack looks like at the time we called “printf”. Similar to the buffer overflow post, let’s load our code in GDB using “gdb ./fmtstr_info_leak.exe -q”. Once we “list” our code, let’s set a breakpoint at line 21.

Figure 4: Code listing in GDB with breakpoint set at line 21.

Once we have our code listing and breakpoint set. Let’s go ahead and “run “%s%s” the program, take a step (“s) and take a look at the stack.

Figure 5: Stack printed

Ok so what do we have above? Let’s break this down.
1 – First up run our code with two format specifiers %s%s
2 – We then stepped once through the program
3 – When we examined 8 hex words (x/8xw) on the stack from the perspective of the $esp register, we see those 8 hex words are printed. For the purpose of this post, the only ones that matter are the first 3 which are selected.

Let’s now analyze this.
4 – In 4, we examined 1 string (x/1s) at memory location ‘0xffffd22d’. Note this value is the same as the first item highlighted in 3. What we see here is our “%s%s”. These are the format specifiers we provided to “printf”. This now means it will pickup the next two strings on the stack.
5 – Here we pickup the next value on the stack which is at memory location “0x08048507”. When we examine that memory location – x/1s 0x08048507 - the value here points to our string “ Guess who's back again? \n”
6 – Similarly, when we examine the memory location at “0x080484e0” – x/1s 0x080484e0, we see our next string.

So as we stated, “printf” expects to have format specifiers. Thus when we provided our two %s%s “printf” picked up the next values from the stack and presented it to us.

Alternatively, we could have printed the stack in hex using “./fmtstr_info_leak.exe "%x %x %x %x"”. This would have produced “8048507 80484e0 0 f7e1caf3”

Defenses – Protecting yourself from this vulnerability
Now believe it or not, fixing this vulnerability is quite easy. Way too easy!! Our code above has “printf(argv[1])”. All we need to do to fix this is “printf("%s", argv[1])”. This would immediately invalidate any attempt to take advantage of this vulnerability.

Your turn! Fix the code and run it again. Post your output in the comments section after you run “./fmtstr_info_leak.exe %s%s” or “./fmtstr_info_leak.exe %x%x%x%x”.


References:
Tim Newsham - Guardent, Inc. - Format String Attacks
Syracuse University Lecture Notes – Format String Vulnerability
Stanford - scut / team teso – Exploiting Format String Vulnerabilities
Saif El-Sherei - Format String Exploitation - Tutorial
Format String Vulnerability I & II
Paul Haas - Advanced Format String Attacks
Stonybrook – Format String Attacks
Wei Wang - Format String Vulnerability
Format String Vulnerabilities
Blind Format String Attacks
SP&E – Buffer Overflow and Format String Overflow Vulnerabilities
USENIX: FormatGuard: Automatic Protection From printf  Format String Vulnerabilities
Yan Huang - Heap Overflows and Double-Free
Lok Kwong Yan - CS392/681 – Polytechnic University - An Introduction to Buffer Overflows and Format String Vulnerabilities
Format string exploitation on windows Using Immunity Debugger / Python
Andreas Thuemmel - Analysis of Format String Bugs

Beginning Stack Based Buffer Overflow

Let’s face it, as a newbie in information security you may hear a lot about buffer overflows but may not have the necessary understanding of what it actually looks like. Most of us know that a buffer overflow entails putting more data into a buffer and causing the program to crash or perform some arbitrary action. This is my attempt to add to the learnings of making buffer overflow easier. You may also see the reference section for some awesome resources to make your learning more interesting and potentially even easier and fun. Note, these are some of the same resources I leveraged when trying to learn buffer overflow. For me, being able to see things from different perspectives help me to understand better, you may be the same or different.

Let’s start by running the code below to see what it does.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
/*
 * bf_vuln.c
 * This program is vulnerable to buffer overflow 
 * and is solely for demonstrating purposes
 * Author: Nik Alleyne < nikalleyne at gmail dot com >
 * blog: http://securitynik.blogspot.com
 * Date: 2017-01-01
 */

 #include <stdio.h>
 #include <unistd.h>

// This will be our arbitrary code
// Nothing malicious just fun
void arbitrary_code()
  {
    printf(" Now you know I should not be seen ! \n");
    printf(" But I am. Don't believe me just watch \n");
  }


//Our vulnerable function
void buffer_overflow()
    {
      //declaring our buffer size of 8 bytes
      char buffer[8];
      //read our input. This 'gets' function is where our problem really lies
      gets(buffer);
      //print the output back to the screen. Simply echo our input back to the screen
      puts(buffer);
    }


int main()
  {
    //we'll print the PID so we can see the stack location using the 'proc' file system
    pid_t pid = getpid();
    printf(" My PID is %d \n ", pid);
    //here we call our function declared above.
    buffer_overflow();
    return 0;
  }
/* Note: Nowhere in the above code did we call 'arbitrary_code'
 * However, we will see shortly that we can exectue this code 
 * by using its memory location
 */


Notice in the code above that “arbitrary_code” function is not being called anywhere.

Let’s compile this code as shown below:
gcc -ggdb -m32 -mpreferred-stack-boundary=2 -fno-stack-protector bf_vuln.c -o bf_vuln.exe

Figure 1: code being compiled.

Note while compiling we are already warned that the “gets” function is dangerous and should not be used.

Now that the code is compiled let’s execute it.

Figure 2: First run with valid input

Above we see our code executed with PID 4298. We also provided the word “Running” as input and this was printed back to the screen.

Now if we were to run this one more time and put more than 8 bytes, we see we get a “Segmentation Fault”. Basically we caused the program to crash.


Figure 3: Input greater than buffer size

Now what did we do to cause the crash?

Before we move on, let’s step back and understand the stack and for our purposes I will keep it extremely, extremely, extremely simple. There are lots of good documentation out there on the stack but the obvious ones for Intel Architecture would be the Intel® 64 and IA-32 Architectures Software Developer’s Manual.

Figure 4: Stack Structure: Source: Intel® 64 and IA-32 Architectures Software Developer’s Manual Volume 1: Basic Architecture

- The stack grows down in memory (towards lesser addresses) when items are pushed on the stack and shrinks up (towards greater addresses) when the items are popped from the stack
- The operating system is responsible for creating stack
- Only one stack - the current stack - is available at a time
- The current stack is the one contained in the segment referenced by the Stack Segment (SS) register
- The stack is typically divided into frames.
- Each stack frame can then contain local variables, parameters to be passed to another procedure, and procedure linking information.
- The stack-frame base pointer (contained in the EBP register) identifies a fixed reference point within the stack frame for the called procedure.
- To use the stack-frame base pointer, the called procedure typically copies the
contents of the ESP register into the EBP register prior to pushing any local variables on the stack.
- Prior to branching to the first instruction of the called procedure, the CALL instruction pushes the address in the EIP register onto the current stack.
- This address is then called the return-instruction pointer and it points to the
instruction where execution of the calling procedure should resume following a return from the called procedure

Ok that’s enough about the for what we would like to do. Now let’s move on.

Now as stated above, the objective in most buffer overflow is to run arbitrary code and in order to do this we need to control the EIP (Instruction Pointer). Additionally, as stated above, the EIP is pushed unto the stack into the return instruction pointer. So if we can overwrite the return pointer with our code, we may be able to perform some arbitrary action.

Let’s revisit our program once again, this time to see where in memory our stack is. This step is not absolutely needed for what we want to do. However, it helps to understand things a bit more.

Figure 5: Memory layout of the stack.

Once we executed our code we saw we got PID “4467”. Looking at the memory “maps” of PID 4467 on the “proc” file system, we see that the stack falls between memory address “fffdd000” and “ffffe000”. Remember we stated above that the stack grows from high memory to low memory. This would mean that the “top” of our stack is “ffffe000” while the bottom would be “fffdd000”.

Let’s move on to loading this program up in the GNU Debugger (GDB) by executing “gdb ./bf_vuln.exe -q”.

Next let’s look at the code using “list” so as to set a breakpoint on line 28.


Figure 6: Code listing and breakpoint being set.

You may have noticed that the listing above, does not show our arbitrary code. We will use that code later though.

Having set the breakpoint, let’s now “run” the program and examine our EBP and ESP registers along with our stack from these perspectives.

First up EBP


Figure 7: GDB output showing EBP and Return Pointer.

If we consider our stack structure diagram from above in figure 4, we know that before the EBP we have the Return Pointer. This is demonstrated above as in EBP has the value of “0xffffcfb8” while the return pointer has the value of “0x08048511”. We can also validate these another way for EBP we can say “print $ebp” and this would show the same “0xffffcfb8”. For the return pointer, we can disassemble the memory address “0x08048511” and we get the following.


Figure 8: Return pointer being validated.

The above image shows that memory address “0x08048511” maps to the next command to be executed after “buffer_overflow” has been called and completed. In this case we are moving “0” into eax which represents what is shown in our code above where we have “return 0”.

At the end of it all, what we really want to do is control the return pointer as to determine what the code does when the value at this address is executed. Our objective then will have to be to overwrite this address.

Let move on and look at things now from the perspective of ESP (stack pointer).


Figure 9: Stack from ESP perspective

From above the offsets to the left confirms that our stack is growing from high memory to low memory. Also if we look at those offsets, we will see that they fall within the memory range showed above in figure 5. Also note that figure 9 above also shows our 8 byte buffer. Do note we are looking at more entries on the stack. In the figure 8 we are examining 4 hex words (x/4xw) from the EBP perspective. In figure 9, we are examining 8 hex words (x/8xw) from the ESP perspective.

At this point what we want to do is fill up our 8 byte buffer with so much information that it overwrites the return pointer and crash. Looking at the image above, we see 8 bytes buffer, 4 bytes EBP and 4 bytes return pointer. So this should mean if we use 16 As (Hex 41), we should be able to overwrite the return pointer with 4As. Let’s test that theory by going back to GDB.

First let’s Step “s” through the program so that it asks for our input.


Figure 10: Buffer filled up and return pointer overwritten with As (Hex 41)

As shown in image 10, we were able to overwrite the return pointer with 0x41414141.

Once we continue with this program it would crash as the memory address would be invalid. However, we’ve manage to learn how much bytes it takes for us to overwrite the return pointer. This information we will use to execute our arbitrary code. Before we exit GDB let’s see where “arbitrary_code” is found in memory. To determine this let’s disassemble this function using “disassemble arbitrary_code”.


Figure 11: arbitrary_code functions starts at memory address “0x080484ad”

Let’s try to use this memory address along with everything else we learned before to our advantage. For us to execute our arbitrary code let use “echo”.

The following one liner will allow us to take advantage of the buffer overflow.
echo -e "AAAAAAAAAAAA\xad\x84\x04\x08" | ./bf_vuln.exe.
What the above line does is fill in our 8 bytes buffer with 8 As then fill in our 4byte EBP with 4 As, then we provide the 4 byte memory address of our “arbitrary_code” to overwrite the return pointer. You may notice the order in which I’ve written the hex value of “arbitrary_code” is the reverse of the way the disassemble presented it. This is because Intel architecture stores data in memory in little endian format.

Figure 12: “arbitrary_code” executed and results shown from our code above.

So we’ve exploited the buffer overflow to run “arbitrary_code”, now how do we prevent this.

Defenses against Buffer Overflow:
First up you should avoid using vulnerable functions and always check your expected input verses what was actually provided by your users. However, there are many different protections mechanisms available. These are typically used in conjunction rather than in isolation.

Data Execution Prevention (DEP):
”DEP is a Windows feature that enables the system to mark one or more pages of memory as non-executable. Marking memory regions as non-executable means that code cannot be run from that region of memory, which makes it harder for exploits involving buffer overruns to succeed.”

Stack Canaries
A canary is a value placed on the stack before  the  saved return address and is an is an effective deterrent against arbitrary code execution.
There are 4 types of canaries
 
–  Random  Canary - A  32-bit  pseudorandom  value  generated  by 
the /dev/random or /dev/urandom devices on a Linux operating system. 
– Random XOR Canary - provides slightly more protection by performing an
XOR operation on the random canary value with the stored control data.
– Null Canary - The canary value is set to 0x00000000, which is chosen based
upon the fact that most string functions terminate on a null value and should not be able to overwrite the return address.
– Terminator Canary  - The canary value is set to a combination of Null, CR, LF and 0xFF.  These values act as string terminators in most string functions and account
for functions that do not simply terminate on nulls
such as gets(). 

Address Space Layout Randomization (ASLR):
ASLR randomizes the memory locations used by system files and other programs, making it much harder for an attacker to correctly guess the location of a given process. Consider our example above where we knew the exact location of the return pointer on the stack. It is quite possible that if we were using ASLR, this location would not have been so easily predictable.

CF Guard
Control Flow Guard (CFG) is a highly-optimized platform security feature was created to combat memory corruption vulnerabilities. It places tight restrictions on where an application can execute code from, thus making it much harder for exploits to execute arbitrary code. CFG extends other mitigations techniques such as /GS, DEP, and ASLR.

As stated above, these defenses are typically used together rather than in isolation. For example on Windows 10, the following can be seen for the “winogon.exe” process.


That’s all folks. Probably one of my longer posts but I believe it was worth it. If you are reading this and think I have miss or miss-represented something, please let me know so that I can fix it.


Enjoy!

References:
Gustavo’s Journey to the stack, part 1
SecurityTube Buffer Overflow Megaprimer
Wikipedia Buffer Overflow
Wikipedia Stack Buffer Overflow
COEN 152 Computer Forensics Buffer Overflow Attack
How Security Flaws Work: The buffer overflow
Buffer Overflows: Attacks and Defenses for the Vulnerability of the Decade
Buffer Overflows: Secure Programming
Buffer Overflows: Vulnerabilities and attacks
Smashing the Stack for Fun and Profit
Linux Journal
SANS Reading Room: Buffer Overflows for Dummies
MIT Open Courseware: Buffer Overflow Exploits and Defenses
Tenouk: A Stack-based buffer overflow
Exploit DB: 64 Bits Linux Stack Based Buffer Overflow
Happy Coding: Print Process ID, etc
Intel® 64 and IA-32 Architectures Software Developer’s Manual
iDefense: A Comparison of Buffer Overflow Prevention Implementations and Weaknesses
Protecting Your Software: Exploit Mitigations in Windows
Stack Smashing as of Today: A State-of-the-Art Overview on Buffer Overflow Protections on Linux_x86_64
Exploit DB: Smashing the stack on modern Linux systems
Control Flow Guard
Exploring Control Flow Guard in Windows 10