ln -s “Exploiting Memory Corruption Bugs in PHP” .

http://www.inulledmyself.com/2015/02/exploiting-memory-corruption-bugs-in.html
http://www.inulledmyself.com/2015/02/exploiting-memory-corruption-bugs-in_23.html
http://www.inulledmyself.com/2015/05/exploiting-memory-corruption-bugs-in.html

An excellent series of three blog posts on the said topic.

Advertisements

Adding EXIF Data Using PHP

A simple PHP script to add image description and geolocation EXIF data to an image. The script makes use of the PHP EXIF Library (PEL) by Isolesen, which can be obtained from http://lsolesen.github.io/pel/.

PHP Code

<?php
set_include_path('lsolesen-pel-9f52634' . PATH_SEPARATOR . get_include_path());
require_once('src/PelJpeg.php');

$pelJpeg = new PelJpeg('in_filename.jpg');

$pelExif = $pelJpeg->getExif();
if ($pelExif == null) {
    $pelExif = new PelExif();
    $pelJpeg->setExif($pelExif);
}

$pelTiff = $pelExif->getTiff();
if ($pelTiff == null) {
    $pelTiff = new PelTiff();
    $pelExif->setTiff($pelTiff);
}

$pelIfd0 = $pelTiff->getIfd();
if ($pelIfd0 == null) {
    $pelIfd0 = new PelIfd(PelIfd::IFD0);
    $pelTiff->setIfd($pelIfd0);
}

$pelIfd0->addEntry(new PelEntryAscii(
        PelTag::IMAGE_DESCRIPTION, 'This is the image description'));

$pelSubIfdGps = new PelIfd(PelIfd::GPS);
$pelIfd0->addSubIfd($pelSubIfdGps);

setGeolocation($pelSubIfdGps, 13.37, 1.337);

$pelJpeg->saveFile('out_filename.jpg');

function setGeolocation(
        $pelSubIfdGps, $latitudeDegreeDecimal, $longitudeDegreeDecimal) {
    $latitudeRef = ($latitudeDegreeDecimal >= 0) ? 'N' : 'S';
    $latitudeDegreeMinuteSecond
            = degreeDecimalToDegreeMinuteSecond(abs($latitudeDegreeDecimal));
    $longitudeRef= ($longitudeDegreeDecimal >= 0) ? 'E' : 'W';
    $longitudeDegreeMinuteSecond
            = degreeDecimalToDegreeMinuteSecond(abs($longitudeDegreeDecimal));

    $pelSubIfdGps->addEntry(new PelEntryAscii(
            PelTag::GPS_LATITUDE_REF, $latitudeRef));
    $pelSubIfdGps->addEntry(new PelEntryRational(
            PelTag::GPS_LATITUDE, 
            array($latitudeDegreeMinuteSecond['degree'], 1), 
            array($latitudeDegreeMinuteSecond['minute'], 1), 
            array(round($latitudeDegreeMinuteSecond['second'] * 1000), 1000)));
    $pelSubIfdGps->addEntry(new PelEntryAscii(
            PelTag::GPS_LONGITUDE_REF, $longitudeRef));
    $pelSubIfdGps->addEntry(new PelEntryRational(
            PelTag::GPS_LONGITUDE, 
            array($longitudeDegreeMinuteSecond['degree'], 1), 
            array($longitudeDegreeMinuteSecond['minute'], 1), 
            array(round($longitudeDegreeMinuteSecond['second'] * 1000), 1000)));
}

function degreeDecimalToDegreeMinuteSecond($degreeDecimal) {
    $degree = floor($degreeDecimal);
    $remainder = $degreeDecimal - $degree;
    $minute = floor($remainder * 60);
    $remainder = ($remainder * 60) - $minute;
    $second = $remainder * 60;
    return array('degree' => $degree, 'minute' => $minute, 'second' => $second);
}
?>

Explanations

set_include_path('lsolesen-pel-9f52634' . PATH_SEPARATOR . get_include_path());
require_once('src/PelJpeg.php');

Import the necessary code. For this script, only PelJpeg.php from the Isolesen PEL library is needed.

$pelJpeg = new PelJpeg('in_filename.jpg');

Load the image file to be editied, in this case, in_filename.jpg.

$pelExif = $pelJpeg->getExif();
if ($pelExif == null) {
    $pelExif = new PelExif();
    $pelJpeg->setExif($pelExif);
}

$pelTiff = $pelExif->getTiff();
if ($pelTiff == null) {
    $pelTiff = new PelTiff();
    $pelExif->setTiff($pelTiff);
}

$pelIfd0 = $pelTiff->getIfd();
if ($pelIfd0 == null) {
    $pelIfd0 = new PelIfd(PelIfd::IFD0);
    $pelTiff->setIfd($pelIfd0);
}

Get the EXIF and the root image file directory (IFD) from the image.

$pelIfd0->addEntry(new PelEntryAscii(
        PelTag::IMAGE_DESCRIPTION, 'This is the image description'));

Add the description (in this case, the description is “This is the image description“.)

$pelSubIfdGps = new PelIfd(PelIfd::GPS);
$pelIfd0->addSubIfd($pelSubIfdGps);

Add a sub-IFD for the geolocation data.

setGeolocation($pelSubIfdGps, 13.37, 1.337);

Set the geolocation data (in this case, with a latitude of 13.37 and a longitude of 1.337). The setGeolocation function is explained below.

$pelJpeg->saveFile('out_filename.jpg');

Save the image which contains the additional EXIF data. In this case, the image is saved to out_filename.jpg.

function setGeolocation(
        $pelSubIfdGps, $latitudeDegreeDecimal, $longitudeDegreeDecimal) {
    $latitudeRef = ($latitudeDegreeDecimal >= 0) ? 'N' : 'S';
    $latitudeDegreeMinuteSecond
            = degreeDecimalToDegreeMinuteSecond(abs($latitudeDegreeDecimal));
    $longitudeRef= ($longitudeDegreeDecimal >= 0) ? 'E' : 'W';
    $longitudeDegreeMinuteSecond
            = degreeDecimalToDegreeMinuteSecond(abs($longitudeDegreeDecimal));

    $pelSubIfdGps->addEntry(new PelEntryAscii(
            PelTag::GPS_LATITUDE_REF, $latitudeRef));
    $pelSubIfdGps->addEntry(new PelEntryRational(
            PelTag::GPS_LATITUDE, 
            array($latitudeDegreeMinuteSecond['degree'], 1), 
            array($latitudeDegreeMinuteSecond['minute'], 1), 
            array(round($latitudeDegreeMinuteSecond['second'] * 1000), 1000)));
    $pelSubIfdGps->addEntry(new PelEntryAscii(
            PelTag::GPS_LONGITUDE_REF, $longitudeRef));
    $pelSubIfdGps->addEntry(new PelEntryRational(
            PelTag::GPS_LONGITUDE, 
            array($longitudeDegreeMinuteSecond['degree'], 1), 
            array($longitudeDegreeMinuteSecond['minute'], 1), 
            array(round($longitudeDegreeMinuteSecond['second'] * 1000), 1000)));
}

The function for setting the geolocation data. This function is needed because the library uses the degree-minute-second format for the latitude and longitude values, so the input decimal values have to be converted beforehand. Also, the library uses positive latitude and longitude values with a direction reference (N or S for latitude, and E or W for longitude), instead of positive and negative values.

function degreeDecimalToDegreeMinuteSecond($degreeDecimal) {
    $degree = floor($degreeDecimal);
    $remainder = $degreeDecimal - $degree;
    $minute = floor($remainder * 60);
    $remainder = ($remainder * 60) - $minute;
    $second = $remainder * 60;
}

The function for converting a decimal degree value to the degree-minute-second format.

Note: php is needed to run the script, and it may not  be present in a default installation. It can be installed through the package manager.

References

[1] http://lsolesen.github.io/pel/
[2] http://www.wikipedia.org/wiki/Exchangeable_image_file_format

Using Flickr API to Get Photo Information

A simple PHP script to get a list of a user’s uploaded photos through the Flickr REST API. For each photo, the script gets its title, description, original photo URL and geolocation.

To use the Flickr API, an API Key (Consumer Key and Consumer Secret) and an OAuth Token (and OAuth Token Secret) are needed. An API Key is obtained by registering a new application (http://www.flickr.com/services/apps/create/apply/), and an OAuth Token is obtained by authenticating the user and granting access to the application (http://www.flickr.com/services/api/auth.oauth.html).

PHP Code

<?php
$page = 1;
$hasMorePhotos = true;
while ($hasMorePhotos) {
    $timestamp = time();

    $url = 'http://ycpi.api.flickr.com/services/rest/';
    $parameters
            = 'extras=description%2Cgeo%2Coriginal_format'
                    . '&format=json'
                    . '&method=flickr.people.getPhotos'
                    . '&nojsoncallback=1'
                    . '&oauth_consumer_key=<consumer_key>'
                    . '&oauth_nonce=0'
                    . '&oauth_signature_method=HMAC-SHA1'
                    . '&oauth_timestamp=' . ((string) $timestamp)
                    . '&oauth_token=<oauth_token>'
                    . '&oauth_version=1.0'
                    . '&page=' . ((string) $page)
                    . '&per_page=500'
                    . '&user_id=me';

    $signatureText = 'GET&' . rawurlencode($url) . '&' . rawurlencode($parameters);
    $signatureKey = '<consumer_secret>&<oauth_token_secret>';
    $signature = rawurlencode(base64_encode(hash_hmac('sha1', $signatureText, $signatureKey, true)));

    $parameters .= ('&oauth_signature=' . $signature);

    $curl = curl_init();
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($curl, CURLOPT_URL, ($url . '?' . $parameters));
    $result = curl_exec($curl);

    $resultJson = json_decode($result, true);

    if (count($resultJson['photos']['photo']) > 0) {    
        foreach ($resultJson['photos']['photo'] as $photo) {
            echo 'ID: ' . $photo['id'] . "\n";
            echo '    TITLE: ' . $photo['title'] . "\n";
            echo '    DESCRIPTION: ' . $photo['description']['_content'] . "\n";
            echo '    URL: ' 
                    . 'http://farm' . $photo['farm'] . '.staticflickr.com/'
                    . $photo['server'] . '/' 
                    . $photo['id'] . '_' . $photo['originalsecret'] . '_o.' . $photo['originalformat'] . "\n";
            echo '    GEOLOCATION: ' . $photo['latitude'] . ', ' . $photo['longitude'] . "\n";
        }
        $page++;
    } else {
        $hasMorePhotos = false;
    }
}
?>

where <consumer_key>, <consumer_secret>, <oauth_token> and <oauth_token_secret> are obtained through the application registration and user authentication process.

Explanations

while ($hasMorePhotos) {
...
}

Each of API call returns a “page” of photo information, which is a list of at most 500 photos. Hence, a loop is needed to retrieve all pages.

    $url = 'http://ycpi.api.flickr.com/services/rest/';

The URL for the API call.

    $parameters
            = 'extras=description%2Cgeo%2Coriginal_format'
                    . '&format=json'
                    . '&method=flickr.people.getPhotos'
                    . '&nojsoncallback=1'
                    . '&oauth_consumer_key=<consumer_key>'
                    . '&oauth_nonce=0'
                    . '&oauth_signature_method=HMAC-SHA1'
                    . '&oauth_timestamp=' . ((string) $timestamp)
                    . '&oauth_token=<oauth_token>'
                    . '&oauth_version=1.0'
                    . '&page=' . ((string) $page)
                    . '&per_page=500'
                    . '&user_id=me';

Form the parameters needed for the API call.

    $signatureText = 'GET&' . rawurlencode($url) . '&' . rawurlencode($parameters);
    $signatureKey = '<consumer_secret>&<oauth_token_secret>';
    $signature = rawurlencode(base64_encode(hash_hmac('sha1', $signatureText, $signatureKey, true)));

The OAuth Signature is generated by hashing the URL and parameters (in lexicographical order), using the Consumer Secret and OAuth Token Secret as hash keys.

    $parameters .= ('&oauth_signature=' . $signature);

Append the generated signature to the request parameters.

    $curl = curl_init();
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($curl, CURLOPT_URL, ($url . '?' . $parameters));
    $result = curl_exec($curl);

Use Curl to make the API request and get the response.

    $resultJson = json_decode($result, true);

Parse the JSON response.

        foreach ($resultJson['photos']['photo'] as $photo) {
            echo 'ID: ' . $photo['id'] . "\n";
            echo '    TITLE: ' . $photo['title'] . "\n";
            echo '    DESCRIPTION: ' . $photo['description']['_content'] . "\n";
            echo '    URL: ' 
                    . 'http://farm' . $photo['farm'] . '.staticflickr.com/'
                    . $photo['server'] . '/' 
                    . $photo['id'] . '_' . $photo['originalsecret'] . '_o.' . $photo['originalformat'] . "\n";
            echo '    GEOLOCATION: ' . $photo['latitude'] . ', ' . $photo['longitude'] . "\n";
        }

Iterate through and print out the returned photo information.

Note: php and php-curl are needed to run the script, and they may not  be present in a default installation. They can be installed through the package manager

References

[1] http://www.flickr.com/services/apps/create/apply/
[2] http://www.flickr.com/services/api/auth.oauth.html
[3] http://www.flickr.com/services/api/flickr.people.getPhotos.html