seoxys.com» Programming http://www.seoxys.com Sun, 30 Sep 2012 22:34:18 +0000 en hourly 1 http://wordpress.org/?v=3.0.1 ATTemplate: Simple Templating System in PHP http://www.seoxys.com/attemplate-simple-templating-system-in-php/ http://www.seoxys.com/attemplate-simple-templating-system-in-php/#comments Wed, 01 Jul 2009 10:13:42 +0000 kenneth http://www.seoxys.com/?p=203 Let me say this first: I do not believe in big bloated MVC PHP frameworks. I believe in having custom code that runs as fast as possible. For recurring useful functionality, such as templates, I believe in using simple, efficient and flexible dedicated standalone modules.

For the past several years, I have been using a home-grown templating system that functioned by parsing template files which would have a dedicated / invented syntax. It would replace, for example, %TAG%, with a value. It had several more advanced features too, such as conditionals, recursion, embedded PHP, and more.

And while it functioned just fine, it implemented a custom parser, and required templates to be written using a non-standard syntax. But, after having used Ruby on Rails, I was inspired to design something better.

ATTemplate is the result of this. The main idea behind ATTemplate is that PHP in itself is already a parser, so why reinvent the wheel?

ATTemplate is very lightweight and relatively simple, but it’s very powerful without being bulky. It allows for everything the other templating systems can do, including loops, nested templates, recursion, conditionals, etc.

How to use

Here’s how you’d use ATTemplate:

<?php

// Include the ATTemplate class
require_once 'attemplate.inc.php';

$template = new ATTemplate();

// Optionally, you can give it properties, like so:
// $template = new ATTemplate($property_array);

$unread_messages = rand(0, 20);

// Sets property 'unread_messages' to 10.
$template->set('unread_messages', $unread_messages);

$template->set('title', 'ATTemplate Test');

$property_array = array(
    'first_name' => 'John',
    'time' => date('H:i:s'),
    'friend_requests' => array(
        array('name'=>'James', 'followers'=>rand(0, 200)),
        array('name'=>'Josh', 'followers'=>rand(0, 200)),
        array('name'=>'Aaron', 'followers'=>rand(0, 200)),
        array('name'=>'Eric', 'followers'=>rand(0, 200)),
        array('name'=>'Mike', 'followers'=>rand(0, 200))
    )
);

// This pushes the content of $property_array into the properties
$template->push($property_array);

// Prints the parsed template
echo $template->parse('index.phtml')

?>

And here’s what your template could look like:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>

    <title><?php echo $title; ?></title>

</head>

<body>

<h1>Welcome, <?php echo $first_name; ?></h1>

<?php if($unread_messages>0): ?>
<h2>You have <?php echo $unread_messages; ?> unread messages!</h2>
<?php endif; ?>

<p>You have received friend requests from the following people:</p>
<ol>
<?php foreach($friend_requests as $friend_request): ?>
    <li><?php echo $friend_request['name']; ?> (has <?php echo $friend_request['followers']; ?> followers)</li>
<?php endforeach; ?>
</ol>

<p>The time is <?php echo $time; ?></p>

</body>
</html>

License

You’re free to use the code in whatever you want, commercial or not. Modify it, redistribute it, do whatever you want with it.

The only requirement is that you need to give me credit.

Also, please do shoot me an email if you use this in your project.

ATTemplate by Kenneth Ballenegger is licensed under the Azure License.

Download

Download ATTemplate!

]]>
http://www.seoxys.com/attemplate-simple-templating-system-in-php/feed/ 2
Dynamic mass vhost with Apache and mod_rewrite http://www.seoxys.com/dynamic-mass-vhost-with-apache-and-mod_rewrite/ http://www.seoxys.com/dynamic-mass-vhost-with-apache-and-mod_rewrite/#comments Wed, 29 Apr 2009 15:57:14 +0000 kenneth http://www.seoxys.com/?p=185 In the process of setting up a new web-server with Mosso’s CloudServer, I came up across an interesting problem that took be the better part of the day to figure out.

The new server is completely unmanaged, which means that I have no web control panel to manage things. But worry not, that’s actually a good thing, because it means I have no web control panel to complicate and fuck up things either.

But it meant I had to setup Apache manually, including the vhosts so that my domain get mapped to the correct content. The problem is I have north of ten domains, each with their own subdomains. I could do it the standard and documented way of adding a VirtualHost for each domain, or I can be clever and have it do the work for me.

My first idea was to go with mod_vhost_alias:

UseCanonicalName Off

LogFormat "%V %h %l %u %t \"%r\" %s %b" vcommon
CustomLog logs/access_log vcommon

VirtualDocumentRoot /home/kenneth/www/%0/public
VirtualScriptAlias /home/kenneth/www/%0/cgi-bin

This worked like magic, automatically translating the domain requested to the path. http://domain.com/* would translate to /home/kenneth/www/domain.com/public/*. But, www.domain.com would translate to a folder named www.domain.com. This meant one of two things: either I had to create dirty symlinks in my www folder, or anybody accessing my domain from the www. subdomain would get a 404 error, both of which are unacceptable.

Another option would be to change that code like such:

VirtualDocumentRoot /home/kenneth/www/%-2.0.%-1.0/public
VirtualScriptAlias /home/kenneth/www/%-2.0.%-1.0/cgi-bin

This works by taking the last two parts of a domain, but it has two big flaws. Firstly, it completely ignores any subdomains. Secondly, it doesn’t work with multiple-tld domains, such as .co.uk domains.

After a whole afternoon of trying different things, I came to the optimal solution, through URL rewriting.

With this solution, domains, whether they have www. or not, map to the same domain.tld folder, and subdomains also map to folders in the same root folder (www, in my case).

UseCanonicalName Off

<Directory /home>
Options FollowSymLinks ExecCGIAllowOverride All
</Directory>

RewriteEngine On

RewriteCond %{REQUEST_URI} !/home/kenneth/www
RewriteCond %{REQUEST_URI} !^/icons/
RewriteCond %{REQUEST_URI} !^/cgi-bin/
RewriteCond %{HTTP_HOST} ^(?:www\.)?(.*)$ [NC]
RewriteRule ^/(.*)$ /home/kenneth/www/%1/public/$1

RewriteCond %{REQUEST_URI} !/home/kenneth/www
RewriteCond %{REQUEST_URI} ^/cgi-bin/
RewriteCond %{HTTP_HOST} ^(?:www\.)?(.*)$ [NC]
RewriteRule ^/(.*)$ /home/kenneth/www/%1/cgi-bin/$1 [T=application/x-httpd-cgi]
]]>
http://www.seoxys.com/dynamic-mass-vhost-with-apache-and-mod_rewrite/feed/ 2
Registration Schemes: Asymmetrical Cryptography http://www.seoxys.com/registration-schemes-asymmetrical-cryptography/ http://www.seoxys.com/registration-schemes-asymmetrical-cryptography/#comments Sat, 05 Apr 2008 22:13:05 +0000 kenneth http://www.seoxys.com/?p=86 One challenge that most developers face when nearing release of their first application is how to implement registration and piracy protection. This three-part article will describe three common types of registration schemes: Serial Numbers, Asymmetrical Cryptographic Keys and Product Activation.


Part Two: Asymmetrical Cryptography

Asymmetrical Cryptographic Keys are a great way to secure you app, because the code used to generate serials is not included in your app, thus removing the risk of a keygen. Using a private key, you sign (or encrypt) some of the user’s details. You then use this singed data as the key to your software, either in the form of a serial, a file, or even an image with the data embedded. You then verify that the signature is valid using the public key in your app.

Example

Start off by generating a set of private and public RSA keys. You can do this by using the following in Terminal.app:

openssl genrsa -out private.pem 2048
openssl rsa -in private.pem -out public.pem -outform PEM -pubout

You can use different size keys. Using a shorter key, such as 512 will make your software more vulnerable to brute-force attack, but has the advantage of making the signature smaller (Which is useful if you wish to display it in the form of a Serial Number).

I believe I used the following set of keys. The keys are also included as files in the source code of this example (available at the bottom of this article).

-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAwKhjrkHmaupDGERSHdgZuSwBWBr4kufBGz0Dk5sn3PR3ZtaP
Vrv6+5Mdz1gAEBYbUVH3m+4+dHcwol5xNckKBT8M5Zy6GPoV9dBUS/1wQBzgdTzf
jvV4uE9S0pofQWw3faZ904tTOjbM0qUko2nd7yyjYBhh/m1ABEFHuL62BvRp13na
vv6534OqqeExEb9VD3K9+Rr4+YQVRUpqZSz2xwhqfLgAzFVQ9bmSG8yTVKmF/vQA
t+N8ThN2WO5qYtCbPawkmIpwvUCTXkxAiiTPNOiU3G1vwtzBoma9TL6dgGmhq6P7
0KBcQNGUEpA2PFC7MEBeNyVyiMIOAvrkHjY/VQIDAQABAoIBABUNET9EMiIykLxB
Etvx9fWWylrPL6QVsLMCOrbROEzbZYSWIzlt9uGwVIyIaBFZ6Qg8tZqTML3XHDhR
q3seCXtDRWx9cJQ0F1wxtFRNUAuhXCFTUnYzekphWIJslse2RGX1YEBSM/jjbgQC
SXuVoMt2jC9+2o5Lb7hHTcfxBsDBmZpghArT5seTOwDOOhTULqoh2wgZYB2IpgTI
UV2CPpAqRVECRnPNdE5UcNIeHc7g4aji5BO0G0u8uM4RUffuRcLaPymuxpU9vwd1
gjVaG6BF/2odW7GEBU3FNLUtvr9MxT+HC+hwOJUuk8NWxU7DqMdyiwSs7W3Nnx7R
5RPvj8ECgYEA34DZjy5EMm7QyPZA6DvAZv6RIecFEwEkwFG+mQgoCy4VfLikkwzC
bI8M8fc6Xiix7ZTjSmvuHt1D4HSRHMOVYgDzY0A5+F+8X657mN5TwNlYMOUkDX3I
rNwc3cRVqtLZYGX0H7cR6eEomGJ7fA9gKuTpaXI0IJz5DsqsgTaGvfECgYEA3Ktr
Q53i52jnssL9c3JsxQO+I/2fWKgo3bZeBI/5zLsz3itVjFjMVldrIK1QZWXI4z7l
dPYwh6qCa1unsizuuzeAhW6NcuUjGPBlBqlo/a9WfOo16ExPXBoH3PH2DXz/YS+D
DOp4Wl8ePhO7C46t3zmGahchysx3kCGkAmNkA6UCgYEA0upvZNUOemFlGiB5RC8O
9KMLJukyOqr7mZoKubOexl4o3NgKRtLlrziXyMe8Bxt0PXYhwBt2TR4Vbf3S60gO
8rte86yqiB8gT1MDRFGazATPWuUCTtECzU2y1/ztsxTjGjtcU4mZmBJpEtTtHzgL
Uq9PLbkeRCCeUD0m6ZEhOqECgYB85jFyNh1F6aSrE56tB2j1Iicu69CTN6rZwuz4
HB3BeXvkFhb3txMBE7244yAMJE5OAT2Ss/3H7AShi2EhgjklkkaWP3qkO3lgFkC4
Qo8Ad4u2bEJS105bzQgCUJl6DPPnKCM+3j98tzXA4R4PbpSPMloYFju0M4LA+6l/
CI6FWQKBgQCWr4Py/GBhgoYOlY/f41NzOfsttwcCBum3uPbiPq6gM/AQQRjzdUmK
QRgG9XXs/33KUMiU+/15hK8ShrOWRSx+zHdgeMhVmuYJdEeygANI9dkonJ3+Olth
77beMQrKIY9kw4bVRFtLWhxfAHXvnksnBg79PX05joVvoHFgVxuwlg==
-----END RSA PRIVATE KEY-----
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwKhjrkHmaupDGERSHdgZ
uSwBWBr4kufBGz0Dk5sn3PR3ZtaPVrv6+5Mdz1gAEBYbUVH3m+4+dHcwol5xNckK
BT8M5Zy6GPoV9dBUS/1wQBzgdTzfjvV4uE9S0pofQWw3faZ904tTOjbM0qUko2nd
7yyjYBhh/m1ABEFHuL62BvRp13navv6534OqqeExEb9VD3K9+Rr4+YQVRUpqZSz2
xwhqfLgAzFVQ9bmSG8yTVKmF/vQAt+N8ThN2WO5qYtCbPawkmIpwvUCTXkxAiiTP
NOiU3G1vwtzBoma9TL6dgGmhq6P70KBcQNGUEpA2PFC7MEBeNyVyiMIOAvrkHjY/
VQIDAQAB
-----END PUBLIC KEY-----

Next, we will create the generator. We will start by concatenating the details (full name and email address) into a single string:

First Last+email@address.com

Then, we will use RSA to sign this string using the private key generated above:

lFZpwJ6GPLXz8sDez033RIxJsN072lOEa0qF+8hQ5KCcZEPQqSBU4MKbW+UJxIfSmKMOBYnVfy/wwAoSxTtqn2JIuAPEJvsTlb0mGH5u7mpxH+FDj2TicoBKephWv7UXP9k10OPA45247+j/u4yKT1UZcq7WjChQ3JoE3wBtEoFucQm8vLk/VqvNaBM1TyNEgwT8FmrKlbK1FNUI8nQ0QOEJ9P8oMAblkWE5kALZZqWnAs6xE7c73sex73t5FvxYRqRDzRDzkjTwK0anXCv8dmeLvnaaHAFcfD5llx09oa89q+wzWucE7V1TsPRYKH1sZsSz5G2xTt2pZrjIoTw5ew==

Note: for this sample app, I explicitly turned off creating newlines in the base64 signature.

The code used for this generator is:

-(IBAction)generate:(id)sender
{
    NSData *privateKeyData = [NSData dataWithContentsOfURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"private" ofType:@"pem"]]];
    NSData *publicKeyData = [NSData dataWithContentsOfURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"public" ofType:@"pem"]]];
    NSString *details = [NSString stringWithFormat:@"%@+%@", [name stringValue], [email stringValue]];

    SSCrypto *crypto = [[SSCrypto alloc] initWithPublicKey:publicKeyData privateKey:privateKeyData];
    [crypto setClearTextWithString:details];

    NSData *signedTextData = [crypto sign];
    NSString *string = [signedTextData encodeBase64WithNewlines:NO];

    [serial setStringValue:string];

    [crypto release];
}

As you can see, I used Septicus Software’s great SSCrypto framework for this task… It makes things so much easier… Unfortunately it doesn’t support base32 or DSA, which would both have helped make more human-friendly keys.

The other piece needed is the validator, used in your software to validate serial numbers. Include only the public key in your app, and use RSA to verify the key.

-(IBAction)validate:(id)sender
{
    NSData *publicKeyData = [NSData dataWithContentsOfURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"public" ofType:@"pem"]]];
    NSString *details = [NSString stringWithFormat:@"%@+%@", [name stringValue], [email stringValue]];
    NSData *number = [[[serial stringValue] dataUsingEncoding:NSUTF8StringEncoding] decodeBase64WithNewLines:NO];

    SSCrypto *crypto = [[SSCrypto alloc] initWithPublicKey:publicKeyData];
    [crypto setCipherText:number];

    [crypto verify];

    if([[crypto clearTextAsString] isEqualToString:details])
        NSRunAlertPanel(@"Result", @"Good serial!", @"OK", nil, nil);
    else
        NSRunAlertPanel(@"Result", @"Wrong serial!", @"OK", nil, nil);

    [crypto release];
}

Important Note: In this sample code, I included both the generator and the validator in the same application. I included the private.pem file in the bundle. You should never do this. If the private key is ever leaked, it compromises the whole security of your application.

Making it safer

You can easily make it more secure by combining this technique with the technique explained in Part One. Instead of simple concatenating the details as I did here, you could use all the techniques applied in Part One, such as using a hash instead, or doing ROT13 on it, or rearranging the order of the characters.

Another thing you should do is to hardcode and obfuscate your public key. Having it as a file in the bundle makes you vulnerable to key substitution. (Basically, a cracker would replace the public key in your app by a different key they created using a private key they know, thus making their licenses valid instead of yours.)

Form Factors

While you may not realize it at first sight, this has become one of the most common methods in Mac shareware, thanks to the open-source framework AquaticPrime. AquaticPrime uses this technique behind the scenes, by embedding the signature in a plist file. AquaticPrime is a very easy way to use this. Unfortunately, if you decide to use AquaticPrime.framework in your app, it is very easy to replace the .framework file with a malicious one that will always claim your licenses are valid.

To date, as far as I know, there isn’t any HackuaticPrime.framework yet, but this might one day become a problem with AquaticPrime gaining popularity thanks to it’s extreme simplicity of implementation.

Update: Devon in the comments suggests implementing a hash check of the framework, which is a simple way of checking the framework’s integrity. Of course, there are still ways to get around it, but this makes it one step more difficult.

Another common form factor for Asymmetrical Cryptographic Keys is custom URL schemes. That’s actually a very clever and convenient way of doing it. To register, the users get to simple click on a link which looks like this: (All the user sees is a nice “Click here to register” link)

myapp://name:email:key

Another clever, but controversial form factor is Agile Web Solution’s 1Password License “Cards”.

And of course, if you find a way to make short base32 signatures (I hear DSA makes short signatures), you can even use longer Serial Numbers.

AHJ53-5HGJZ-8DG8R-284DF-56FJB-74FH4-FJUEH


Sample Code

The code used in this article can be downloaded here.
As always, licensed under MIT license. If you do use it, mention it in the About Box or readme.txt.


Part One: Serial Numbers
The next part will be coming soon.

]]>
http://www.seoxys.com/registration-schemes-asymmetrical-cryptography/feed/ 7
Registration Schemes: Serial Numbers http://www.seoxys.com/registration-schemes-serial-numers/ http://www.seoxys.com/registration-schemes-serial-numers/#comments Thu, 03 Apr 2008 21:26:56 +0000 kenneth http://www.seoxys.com/?p=85 One challenge that most developers face when nearing release of their first application is how to implement registration and piracy protection. This three-part article will describe three common types of registration schemes: Serial Numbers, Asymmetrical Cryptographic Keys and Product Activation.


Part One: Serial Numbers

Serial numbers are the simplest, most practical option. However, they are also the least secure. It consists of taking at least one of the customers’ details, and creating a serial number from it. The serial number is usually tied to either the customer’s name, or his email address, preferably both.

For example, let’s say the customer’s name “First Last” and his email address is “email@address.com”. The first step would be to strip his name and email address of any non-alphabetical characters, concatenate it and convert it to uppercase. (I put the email address first, because it’s less recognizable) Here’s what we get:

EMAILADDRESSCOMFIRSTLAST

Now map this string onto a XXXX-XXXX-XXXX-XXXX-XXXX key. If there are any character leftovers, just discard them. If there aren’t enough characters to fill all the Xs in, leave them as something constant. (they don’t have to be all the same, but they have to be the same for each position all the time. You could for example say you’re mapping it onto an QRST-ABCD-IJLK-EFGH-MNOP key, and leave unfilled spaces as is)

EMAI-LADD-RESS-COMF-IRST

Then, we’d apply ROT13 on it.

RZNV-YNQQ-ERFF-PBZS-VEFG

Lastly, we could replace any swearwords in the key by some random other constant text, just in case.

Another example, using a similar method: Using the same customer, here’s what we’d do. Take his details, concatenate and salt them:

First Last+random salt+email@address.com

Then, MD5 the result and add another salt:

salt+0fb61d4a0f894c63d3ddbd8388404b6c

Next, SHA1 the result:

28a8275bdcbca542f567efef9cc4db2150c38900

And finally, uppercase it and map it onto a XXXX-XXXX-XXXX-XXXX-XXXX serial:

28A8-275B-DCBC-A542-F567

When you have decided on a serial scheme, implementing it is easy. Upon registration, you take the buyer’s name and email address, and generate a serial from it. He then has to input this serial into you app, along with his name and email address. All you have to do in you app is take the name and email address he gave you, generate a serial from it, and check it against the serial he gave you.

Making it more secure

For security reasons, one important step to take is obfuscating how you create those serials, in case anyone tries to create a keygen for you app. The easiest way is adding dummy maths code in the middle of the code where you work out your serial. It will not affect your serial, but it will show up in the assembly code in case anyone tries to gdb your app (more on that in another blog post I have planned).

Another quick thing you could do is shuffle the characters a bit on a set pattern to make them less obvious.

For example you could use this pattern:

ABCD-EFGH-IJKL-MNOP-QRST

becomes

TMLN-DQGA-ISPC-BEOK-FJRH

Stand-alone serials

Sometimes, your serials cannot be tied to any of the customer’s data, for example for retail sales. In that case, you’d need a different serial scheme. You need to choose certain characteristics / rules that make a serial valid. It could be as simple as checking that the 19th character is a W.

Here’s a set of example rules you could use:

  • The ASCII value of the first character of all five blocks of four characters have to add up to 100.
  • The last character of all five blocks of four characters have to be vowels.
  • The first character of either block 3 or 4 has to be E.
  • The ASCII value to the third character of every block have to be even numbers.

In your apps, just check the serial against the rules, and if it’s correct, you can assume it is a correct serial.

For your generator, you can have a pre-made list of valid serials, and assign them to a customer or print them on a retail copy when needed. The problem with this method is that you can eventually run out of valid serials. In which case you would have to generate a new batch of serials, or reassign already used serials to a second customer.

Another (better) way of doing stand-alone serial numbers is splitting the serial number in two, and basing the second part on the first part. [thanks to tomasf from the #macsb IRC channel for this method]

For example, in a serial number ABCD-EFGH-D07A-A959-F269, separate the first eight characters from the rest of the serial:

ABCDEFGH

Salt it:

saltyABCDEFGH+123

MD5:

d07aa959f269104ab28e2a748c415c5c

Map it onto XXXX-XXXX-XXXX:

D07A-A959-F269

And check it against the second part of the serial. In this example, the serial is correct.


Part Two: Asymmetrical Cryptographic Keys
The last parts will be coming soon.

]]>
http://www.seoxys.com/registration-schemes-serial-numers/feed/ 7
Interviews and Podcasts http://www.seoxys.com/interviews-and-podcasts/ http://www.seoxys.com/interviews-and-podcasts/#comments Sat, 15 Mar 2008 09:58:13 +0000 kenneth http://www.seoxys.com/interviews-and-podcasts/ iAppblog recently interviewed me on the new iPhone SDK, Apple’s business model, and whether we will see Exces for iPhone. It’s an interesting read, so be sure to go have a look

Last week, I also participated in the MacSB podcst episode 4. It was really interesting and instructive to have a chat with some really cool other developers: Mike Lee, John Fox, Danny Greg, and our host, Steve Scotty.

]]>
http://www.seoxys.com/interviews-and-podcasts/feed/ 0
New Design! http://www.seoxys.com/new-design/ http://www.seoxys.com/new-design/#comments Mon, 10 Mar 2008 19:53:32 +0000 kenneth http://www.seoxys.com/new-design/ Here’s a fresh new look for my blog!

I’m hoping this will look slick and professional.

I’m aware it isn’t totally finished: it brings IE down to its knees, and some parts don’t look quite right in Opera. I will do my best to fix these issues ASAP. If this is the case for you, I suggest you upgrade to a more modern browser.

Feedback is welcome! Tune in in the comments to see how much they rock. My comments show up purple, while the rest are yellow. It also uses a speaking verb at random from a hardcoded list, because it’s cool!

And be sure to click on the photo that sticks out.
It’s free, good-looking self-promotion.

This was mostly designed by Ernest Liu. Check him out, he rocks!

]]>
http://www.seoxys.com/new-design/feed/ 2
NanoLifeSaver http://www.seoxys.com/nanolifesaver/ http://www.seoxys.com/nanolifesaver/#comments Sat, 23 Feb 2008 23:06:43 +0000 kenneth http://www.seoxys.com/nanolifesaver/ I bring to you, NanoLifeSaver.

NanoLifeSaver is a slick Core Animation screensaver.


(This last one is a movie, Click to Play)

Download NanoLifeSaver

Credit goes to Scott Stevenson for coming up with the original animation code.

]]>
http://www.seoxys.com/nanolifesaver/feed/ 10
R.I.P. Hijack http://www.seoxys.com/rip-hijack/ http://www.seoxys.com/rip-hijack/#comments Fri, 22 Feb 2008 14:27:05 +0000 kenneth http://www.seoxys.com/rip-hijack/ Disappointingly, codename: Hijack / Spool is no more.

I have posted about this project before, and it was really something I was excited about.

Back in the day where I actually had time, I was a forum freak and was active in more than 10 forums… This would have been the dream app for me.

Unfortunately, Hijack has just been open-sourced. Which means that the project is essentially dead.

]]>
http://www.seoxys.com/rip-hijack/feed/ 2
An introduction to Sean Collins http://www.seoxys.com/an-introduction-to-sean-collins/ http://www.seoxys.com/an-introduction-to-sean-collins/#comments Thu, 22 Nov 2007 08:59:12 +0000 kenneth http://www.seosoft.info/seolog/2007/11/22/an-introduction-to-sean-collins/

From: Sean Collins
Date: July 23, 2007 4:32:35 PM EDT
To: [anonymous@gmail.com]
Subject: Aquatic Prime

I recently read your blog post about Aquatic prime, after I was hunting around inside another application.

I would like to perhaps exchange some notes, because I think I might have found at least an individual application that uses the PHP authentication of the AquaticPrime framework, and I suspect that it would be vulnerable to SQL Injection attacks, as well as using what I believe to be, a cookie that never expires that is baked into the executable, which could lead to some other interesting things.

Let me know if you’d be interested in a chat!

Thank You,
Sean Collins

1:42:24 PM seanwdp: [Hey], it’s Sean C
1:42:48 PM anonymous: hey sean.
1:43:10 PM seanwdp: The app in question is called Exces
1:43:22 PM seanwdp: part of that MacHeist deal they were doing a week ago
1:43:35 PM anonymous: ok
1:43:58 PM anonymous: and what can you do exactly? (re-reading your email)
1:44:13 PM seanwdp: I don’t have any POC just yet, just some leads.
1:44:41 PM seanwdp: just looking through the executable, found some little things
1:45:04 PM seanwdp: the app uses the PHP part of the AP framework
1:45:14 PM seanwdp: to do registration keys and such
1:45:20 PM anonymous: k
1:45:44 PM seanwdp: let me give you the executable dump
1:45:55 PM anonymous: k
1:47:27 PM anonymous: can i just strings it?
1:47:57 PM seanwdp: yeah, already did and sent it to you as a txt
1:48:52 PM seanwdp: one of the stings contains his license check
1:48:53 PM anonymous: ok
1:48:59 PM seanwdp: it’s a PHP script
1:49:09 PM seanwdp: if you connect to it with just a browser you get a bunch of mysql errors
1:49:10 PM anonymous: http://www.seosoft.info/app_rsrc/exces_licence_check.plist.php
1:49:13 PM anonymous: yeah i see
1:49:14 PM seanwdp: exactly
1:49:23 PM seanwdp: so I think that the cookie is a few lines below
1:49:25 PM seanwdp: that has the login data
1:49:43 PM anonymous: and that is based on the AP sample code you think?
1:49:52 PM seanwdp: I’m not entirely sure
1:49:59 PM seanwdp: If it is the AP sample code
1:50:02 PM seanwdp: that’s pretty bad
1:50:11 PM seanwdp: I was going from the thinking that he tried to extend the AP
1:50:18 PM anonymous: so have you actually tried to inject anything?
1:50:32 PM seanwdp: I’ve been looking for a way to feed it some bad data
1:50:38 PM seanwdp: I was doing some pretty simple stuff
1:50:47 PM seanwdp: the license key I think is through stenography
1:50:57 PM seanwdp: so I was trying to see what it takes as a dragging source
1:51:12 PM seanwdp: see if I could craft some bad data, then capture the packets
1:51:22 PM anonymous: heh ok
1:51:30 PM seanwdp: What makes me wonder, is the fact that he has another part, his bug reporting
1:51:39 PM anonymous: ap uses real encryption though
1:51:51 PM seanwdp: right
1:51:52 PM anonymous: no stenagraphy no faking
1:52:13 PM seanwdp: but my thinking is that the app will send a user/pass
1:52:30 PM seanwdp: since you get the error about not having a user or database selected
1:52:35 PM seanwdp: when you visit that register page
1:53:22 PM anonymous: what user/pass?
1:53:28 PM anonymous: a bit confused
1:53:44 PM seanwdp: okay. Know how you visit that registration page with a regular browser?
1:53:53 PM anonymous: y
1:54:10 PM seanwdp: notice those mysql errors
1:54:16 PM anonymous: right right
1:54:22 PM seanwdp: Line 2 is the host
1:54:27 PM seanwdp: line 3 is the database
1:54:46 PM anonymous: looks like he’s on a dreamhost box
1:54:50 PM seanwdp: right
1:54:59 PM seanwdp: I’m thinking those variables
1:55:02 PM seanwdp: the PHP ones
1:55:22 PM seanwdp: that set the host, database name, and possibly user/password combo are in the app
1:55:26 PM anonymous: ok
1:55:32 PM anonymous: i’d be real surprised
1:55:36 PM seanwdp: as would I
1:55:48 PM anonymous: in fact i doubt its likely at all
1:56:05 PM anonymous: knowing dreamhost (used to be a customer) they firewall off the mysql server
1:56:24 PM anonymous: the info would be embedded in the php
1:56:33 PM anonymous: it looks to me as if the guy has a f-ed up php
1:56:45 PM anonymous: either the mysql server is down, or something is misconfigured
1:56:52 PM anonymous: i dont think the username password are in the app
1:56:56 PM anonymous: unless you’ve found them?
1:57:08 PM seanwdp: only guesses at this point, nothing jumped out in the strings
1:57:14 PM anonymous: what happens when you packet sniff?
1:57:23 PM seanwdp: still trying to get that running
1:57:27 PM anonymous: ok
1:57:29 PM seanwdp: I might have to do what you did
1:57:33 PM seanwdp: with the code injection
1:57:37 PM seanwdp: just force it to connect
1:57:43 PM anonymous: ah
1:57:54 PM anonymous: so it doesn’t connect to that url normally?
1:58:02 PM anonymous: until you register it perhaps?
1:58:05 PM seanwdp: yeah
1:58:08 PM seanwdp: and there’s a cookie
1:58:13 PM seanwdp: expires never
1:58:27 PM seanwdp: I wondered if that might be a good lead.
1:58:33 PM anonymous: AP is designed for client side validation
1:58:39 PM anonymous: he’s doing it server side too perhaps
1:59:03 PM seanwdp: I mean the guy just sold like 100k licenses or something
1:59:09 PM anonymous: no shit?
1:59:11 PM seanwdp: yeah
1:59:12 PM seanwdp: macheist
1:59:16 PM seanwdp: so I mean, it’s gotta work
1:59:19 PM anonymous: heh
1:59:20 PM anonymous: yeha
1:59:24 PM anonymous: unless it is a dead url
1:59:29 PM anonymous: isn’t used any more
1:59:33 PM anonymous: or is in there to throw you off ;-)
1:59:34 PM seanwdp: true, maybe he baked a new version for macheist
1:59:39 PM anonymous: maybe
1:59:53 PM seanwdp: I dunno, I can’t imagine him being too smart
2:00:06 PM seanwdp: his app just hands off the dirty work to disk utility
2:00:09 PM anonymous: i’d _hope_ he is if he’s releasing an encryption app
2:00:11 PM anonymous: ah
2:00:12 PM anonymous: haha
2:00:19 PM seanwdp: yet still manages to have a “limit” of 10gb
2:00:26 PM seanwdp: for his “vaults”
2:00:48 PM seanwdp: it’s right in the code, he calls hdiutil
2:01:03 PM seanwdp: all he’s got is a pretty GUI
2:01:31 PM anonymous: yeah
2:01:35 PM anonymous: another Disco app
2:01:38 PM seanwdp: yep.
2:02:00 PM seanwdp: At least Disco has “ismoke”
2:02:05 PM seanwdp: :D
2:03:30 PM seanwdp: so what are your thoughts?
2:04:17 PM anonymous: i dunno. i’d be really surprised if the app relies on it for registration
2:04:30 PM anonymous: AP is vulnerable once you have it in your hands.
2:04:44 PM anonymous: it just depends on how much work the guy has done to obfuscate it
2:04:56 PM anonymous: and even then you can always find (and then replace) the public key used
2:05:04 PM seanwdp: right
2:05:11 PM seanwdp: but what about the risks to his website
2:05:20 PM anonymous: i’d be surprised if there are any
2:05:28 PM anonymous: it could just be the mysql server is fubared
2:05:32 PM anonymous: something is misconfigured
2:05:41 PM anonymous: hard to say
2:05:50 PM anonymous: any badly written php could be vulnerable
2:05:54 PM seanwdp: right
2:06:04 PM anonymous: to find out for sure you need to sniff the packets and find out what it sends
2:06:07 PM seanwdp: well I mean he has a bug reporter, where all the stuff is sent using the $_GET array
2:06:19 PM anonymous: any suspicious looking printf style strings?
2:06:32 PM anonymous: stuff that could be a http url request?
2:06:47 PM anonymous: “%@&%@&%@” type stuff?
2:07:01 PM seanwdp: lemme see
2:07:09 PM anonymous: you could try hacking the bug reporter
2:07:11 PM seanwdp: I swear I saw some
2:07:22 PM anonymous: if that is vulnerable then the license check probably is too
2:07:27 PM seanwdp: yeah
2:07:40 PM seanwdp: I mean, it’s much easier to crack the bug reporter
2:07:52 PM seanwdp: since I guess the database connection info is in the script
2:07:56 PM seanwdp: *not guess
2:07:59 PM seanwdp: it is
2:08:07 PM anonymous: that makes no sense
2:08:08 PM anonymous: why do that?
2:08:16 PM seanwdp: pulled it out of a php book
2:08:16 PM anonymous: easier for it to be server side
2:08:24 PM anonymous: if he has to change the password he’d be fucked
2:08:26 PM seanwdp: right, that’s what I’m saying
2:08:27 PM anonymous: or whatever
2:08:34 PM seanwdp: he’s probably got a mysql_connect.php
2:08:46 PM seanwdp: that has a username, password, host, and all that
2:08:54 PM anonymous: but even then he’d have to jump through hoops to expose his mysql server to the world
2:08:59 PM anonymous: by default DH firewalls it
2:09:07 PM anonymous: so you have to assume he knows how to do that at least
2:09:12 PM seanwdp: yeah
2:09:21 PM anonymous: which is inconsistent with him putting his password in the client
2:09:31 PM seanwdp: it would be
2:09:46 PM seanwdp: it’s just that you don’t get the same error reporting on the bug page as the license page
2:10:15 PM seanwdp: but that could be because someone wrote the bug script better
2:10:24 PM seanwdp: and it doesn’t give out those errors to the user
2:10:38 PM seanwdp: meanwhile someone far dumber left the error reporting on, for the license script
2:11:59 PM anonymous: well focus on the bug reporter see if you can capture what it sends
2:12:05 PM anonymous: i’d be interested to see that
2:15:46 PM seanwdp: yeah
2:15:58 PM seanwdp: I’m pretty sure it just sends three or four variables
2:16:06 PM seanwdp: the PHP script gets them and off they go into the database
2:16:12 PM seanwdp: since they’re right in the url
2:16:23 PM seanwdp: http://www.seosoft.info/app_rsrc/bug_send.php?
lang=%@&product=Exces&name=%@&email=
%@&description=%@&explanation=%@
2:16:52 PM anonymous: yeah
2:17:15 PM anonymous: so do some injection :-)
2:24:07 PM seanwdp: I’ll let you know what I come up with
2:24:20 PM anonymous: cool
2:24:26 PM seanwdp: work finally threw up their hands and let me run our stuff on Apache
2:24:39 PM seanwdp: the guy running the server (win2003) has NFC
2:24:47 PM seanwdp: and i don’t like or care about IIS
2:24:56 PM seanwdp: thing spent more time broken then up and running

‘Nuff said.

]]>
http://www.seoxys.com/an-introduction-to-sean-collins/feed/ 1
Trail-ware limitation http://www.seoxys.com/trail-ware-limitation/ http://www.seoxys.com/trail-ware-limitation/#comments Wed, 08 Aug 2007 12:04:59 +0000 kenneth http://www.seosoft.info/seolog/2007/08/08/trail-ware-limitation/ A topic I feel strongly about is trial-ware limitation. The most used solution these day is time limitation, and I hate it.

On the MacSB mailing list:

Hi all,

I’ve got a client who really wants me to work up an expiring trial-ware system
for one of their
 apps.

However, I have to say that I’m always really wary of such solutions. I regard
them as easily
hacked (vs., say, a build that just doesn’t contain certain features) and
bypassable; therefore,
I usually try to steer clients away from them, and don’t use them in my own
 stuff.

But, I’ve known these people a long time, and don’t want to just give them a
“gut reaction”
answer. I thought I’d ask here first to see if anyone has any real-world
experience in favor of
either solution.

For that matter, if anyone is willing to discuss how they created a good
expire-ware solution,
I’d love to hear about it.

Many thanks,

B

My reply:

I don’t like either expiring demos nor feature limitation because of the following reasons:

Expiring demos: Easily hackable (easiest to hack, infinite demos). Say a user tries out V1.0, but doesn’t like it. When V2.0 comes out, he hears good about it, but can’t try it and therefore will not buy it.

Feature-limited demos: Can’t try out the full product.

What I prefer, and what I do is Nagging.

It works surprisingly well. It’s timeless, and annoys the hell out of the future customer without impairing functionality.

There’s different kind of nagging:

-iGetter/Ambrosia-style nagging. You gotta wait for a minute or so before being able to use the software.
-Exces-style nagging. A nag comes up periodically. The user can immediately close it, but it comes up in front-most ever so often.
-The 3rd nagging style is where a window is constantly open (user can’t close it) reminding the user to register. That’s IMHO the most annoying one.

Cheers,
 Kenneth

]]>
http://www.seoxys.com/trail-ware-limitation/feed/ 0