Alun’s code – Page 3 – Tales from the Crypto

Alun’s code

MVP news

My MVP award expires on March 31

So, I’ve submitted my information for re-awarding as an MVP – we’ll see whether I’ve done enough this year to warrant being admitted again into the MVP ranks.

MVP Summit

Next week is the MVP Summit, where I visit Microsoft in Bellevue and Redmond for a week of brainwashing and meet-n-greet. I joke about this being a bit of a junket, but in reality, I get more information out of this than from most of the other conferences I’ve attended – perhaps mostly because the content is so tightly targeted.

That’s not always the case, of course – sometimes you’re scheduled to hear a talk that you’ve already heard three different times this year, but for those occasions, my advice would be to find another one that’s going on at the same time that you do want to hear. Talk to other MVPs not in your speciality, and find out what they’re attending. If you feel like you really want to get approval, ask your MVP lead if it’s OK to switch to the other session.

Very rarely a talk will be so strictly NDA-related that you will be blocked from entering, but not often.

Oh, and trade swag with other MVPs. Very frequently your fellow MVPs will be willing to trade swag that they got for their speciality for yours – or across regions. Make friends and talk to people – and don’t assume that the ‘industry luminaries’ aren’t willing to talk to you.

Featured TechNet Wiki article

Also this week, comes news that I’ve been recognised for authoring the TechNet Wiki article of the Week, for my post on Microsoft’s excellent Elevation of Privilege Threat Modeling card game. Since that post was made two years ago, I’ve used the deck in a number of environments and with a few different game styles, but the goal each time has remained the same, and been successfully met – to make developers think about the threats that their application designs are subject to, without having to have those developers be security experts or have any significant experience of security issues.

What else I did at Black Hat / DefCon–the Core DataMatrix Contest

Black Hat, and its associated sideshow, DefCon, consists of a number of different components. Training, Briefings, Exhibition and Contests, all make up part of Black Hat, and DefCon is a looser collection of Workshops, Events, Parties, Talks, Villages, Contests and numerous other things besides(*).

Perhaps the thing that gave me the most fun this year was the contest that I entered at Black Hat and at DefCon. The contest was run by Core Labs, a part of Core Security Technologies, and featured the theme of reverse engineering.

Reverse Engineering is the skill of looking at someone else’s code – in source code or binary form – and figuring out what the code does, and more importantly, how best to make it do what you want. This often involves exceeding the original design specifications – which is perhaps the simplest and most inclusive definition of “hacking”.

In the DataMatrix contest, the code (or at least, a portion of it) is given to you in source form, in C#. You are told that this code is running as part of a server, and you are given access to the server in the form of two webcams and an output screen. The output screen displays a score sheet, the views from each webcam, and a ‘debug’ output window. I’ve lost the link to the Black Hat version of the code, but here’s the DefCon code.

The webcams are the only form of input to the server that are available to the contestants. Each contestant is given a DataMatrix containing their activation code. This is a bitmap (kind of like a two-dimensional barcode) with some “registration” values around the edge, and squares either black or white in the middle.

And that’s it – that’s all the help you get.

But then, that’s probably all the help you’ll need.

The first challenges

The first challenges are relatively easy. First, you activate your userid by showing the webcam your initial card, and then you see there’s a function called “process_activate” – that sounds like it’s the function that was used to activate your card.

It’s fairly simple to see that this must use the single byte command (in the “cmd” variable) “1”, along with your two byte userid and four byte password, to register you in the system as an active user. It also increases a user-specific value, “score”. To make this easy to understand, we’ll call this “scoring a point”.

Then you see a function “process_free” – from the code, this is clearly a free point. All you need is a command “10”, and your userid, to score a point.

Another function, “process_pieceofcake”, is almost as easy. Command 11, and your userid, plus another four bytes which are simply the two’s-complement of your userid. Easy. In fact, in the Black Hat version, this was even easier, if I remember correctly, but I don’t have the code handy.

“process_name” is clearly one to call early on, because it gets you the bragging rights of putting your own name in the high score table. Plus, it gives you five points more. Pretty good, huh? By now you should have eight points.

Some more interesting challenges

“process_regalo” took my interest next, since it talks about a “gift_list”. Regalo is, apparently, Spanish for “gift”. This one’s strange, because the process has some activity even when the command code isn’t the code expected.

So, I took a look at what that path does. Checks four bytes for the user’s password, and if the “data_regalos” value for this user is less than 10, increments it, and then assigns an extra point to a randomly selected member of the gift list.

Having figured that out, I realised that the quicker I get on the gift list, the quicker I start racking up the points. So, I solved the little coding conundrum (did you figure that one out yourself?) in the other path of process_regalo, and added myself to the gift list.

Five times.

Yeah, five times – did you spot that in the code?

“process_fabe” and “process_fabe13” – those were a little harder. You have to not only crack an MD5 hash (not difficult, but hard), but in the “fabe13” case, figure out what the appropriate “encode” is for the “decode” function. [ROT13, if you didn’t get it]

“process_enqueue” – nasty, this one sends a message to an email address at mailinator.com that you have to figure out for yourself. I still haven’t figured it out. So, I also haven’t got the points from “process_claimMessage”.

“process_sync” was one function where I knew I had an advantage. It requires the use of a .NET Random function, and because I spend a fair amount of my development time in .NET, I knew that I could use my own system to figure out what times the sync function was expecting me at. Occasionally, the webcams weren’t reading my cards quickly enough, but that’s OK. I didn’t necessarily need a whole lot of those points.

Ladies and Gentlemen, we have a winner!

So, as you’ve probably guessed by now, using these functions I managed to rack up quite a number of points, and as it happened, I conquered the Black Hat competition. 60 points to me, 27 to my nearest opponent.

As a result of this, I am now the proud owner of an iPad. Yes, I know, all those things I’ve always said about Apple, and here I am, walking away from a competition with an iPad 2. The irony is almost unbearable. I’ll tell you later what I think of the iPad.

Then comes DefCon

DefCon started out much the same – I was streaking ahead of the competition, largely because the contest was better attended, and I’d already got my foot into the gift_list early on.

Then I saw the part of the server code that was new – it allowed you to write a limited form of program to execute on the server, that would randomly add points to your score. I entered that, and sure enough, I got a pile of points very quickly – about twice as many as I had at Black Hat.

I thought that meant I was going to win the prize.

Sadly, I hadn’t taken into consideration that this was DefCon. The people there are sometimes more devious (though there are also an awful lot of wannabes).

Sure enough, two of my competitors executed the portion of code that allowed them to dump out the list of executing code, as well as to remove the code sample I had submitted. That way, they could copy my code in order to give themselves points, and remove my ability to add points.

In a way, I almost felt like this was kind of cheating – what, they couldn’t write their own code? But, realistically, this was simply a part of the challenge – if I had been as good at reverse engineering as I felt I was, and a little less cocky, I would have spotted this functionality and taken advantage of the means with which to prevent it.

As it was, I came in third, and won a t-shirt. But the joy of winning the Black Hat contest is still something I’m proud of, and grateful to Core for letting me play their games.

If .NET is so good, why can’t I…?

OK, so don’t get me wrong – there are lots of things I like about .NET:

  • I like that there are five main programming styles to choose from (C#, Visual Basic, F#, PowerShell and C++)
  • I like that it’s so quick and easy to write nice-looking programs
  • I like the Code Access Security model (although most places aren’t disciplined enough to use it)
  • I like the lack of remote code execution through buffer overflow

And up until recently, when all I was really doing was reviewing other people’s .NET code, my complaints were relatively few:

  • Everything’s a bloody exception – even normal occurrences.
    • Trying to open a file and finding it not there is hardly an exceptional circumstance, for instance.
    • Similarly, trying to convert a text string to a number – that frequently fails, particularly in my line of work.
    • Exception-oriented programming in general gets taken to extremes, and this can lead to poor performance and/or unstable code, as programmers are inclined either to catch everything, or accept code that throws an exception at the slightest nod.
  • It’s pretty much only available on the one platform (yes, Mono, but really – are you going to pitch your project as running under Mono on Linux?)
  • You can’t search for .NET specific answers in a generic way.
    • “Java” occurs sufficiently infrequently in any programming context other than the Java platform / language, so you can search for “string endswith java” and be pretty sure that you’re looking at the Java string.endsWith member, rather than any other.
    • I’ve taken to searching for “C#” along with my search queries, because the hash is less likely to be discarded by search engines than the dot in “.NET”, but it’s still not all that handy.

But now that I’ve started trying to write .NET code of my own, I’m noticing that there are some really large, and really irritating, gaps.

  • Shell properties in Windows – file titles, description, comments, thumbnails, etc.
    • While there are a couple of additional helpers, such as the Windows API Code Pack, they still cause major headaches, and require the inclusion of another framework that is not maintained by usual update procedures.
    • Even with the Windows API Code Pack, there’s no access to the System.Thumbnail or System.ThumbnailStream properties (and presumably others)
  • Handling audio files – I was hoping to do some work on a sound file analyser, to determine if two allegedly-similar half-hour recordings are truly of the same event, and maybe to figure out which one is likely to be the better. I didn’t find any good libraries for FFT. Maybe this was because you just can’t search for .NET-specific FFT libraries.
  • Marshalling pointers in structs.
    • So many structures consist of lists of pointers to memory contents, it would be really nice to create this sort of a structure in a simple byte array, with offsets instead of pointers, and have the marshalling functions convert the offsets into pointers (and back again when necessary).
    • Better still, of course, would be to have these structures use offsets or counts instead of pointers, but hey, you have to support the existing versions.

So now I have to grapple between whether I want to write my applications in .NET and miss out on some of the power that I may want later in the app’s development, or carry on with native C++, take the potential security hit, but know what my code is doing from one moment to the next.

What other irritating gaps have you seen – or have you found great ways to fill those gaps?

Black Hat with Amazon.com–2011 Code Challenges II

The second day of Black Hat, and we’re showing three coding challenges. [Sorry this post took a while to make – but I hope you’ll agree that the new code formatting makes it easier to read]

As usual, the challenge is to figure out where the flaws lie, and for bonus points, to decide how you would prevent such flaws from happening throughout your own enterprises.

If you want to skip the code challenges, and get straight to the rewards, email security-ninjas@amazon.com or http://security.amazon-jobs.com/jobs.html to get details on the job opportunities we have for all manner of security professionals in Seattle, Dublin, Virginia and Bangalore.

Challenge III – GetSignInResult

Here’s a short stretch of code from an authentication function – how long does it take you to spot the security flaw?

   1: SignInResult *getSignInResult(

   2:         const UserViewImpl *in,

   3:         const char *password )

   4: {

   5:     LdapAuthenticator *ldap = LdapAuthenticator::getInstance();

   6:     SignInResult *out = new SignInResult();

   7:     if( in == NULL || in->getUserId() == NULL ) { 

   8:         LogDebug( kFuncName.c_str(), "UserNotFound" );

   9:         out->setStatus( SignInStatus::UserNotFound );

  10:         return out;

  11:     }

  12:     if( !in->getAccountId() ) {

  13:         LogDebug( kFuncName.c_str(), "AccountNotFound" );

  14:         out->setStatus( SignInStatus::AccountNotFound );

  15:         return out;

  16:     }

  17:     out->setUserId( in->getUserId()->getId());

  18:     out->setAccountId( in->getAccountId()->getId());

  19:     AuthCodec *authCodec = AuthCodec::getInstance();

  20:     AuthToken authToken ( authCodec, in->getAccountId()->getId() );

  21:     out->setAuthToken( authToken.getEncodedAuthToken() );

  22:     CSRFToken csrfToken( authCodec );

  23:     out->setCsrfToken( csrfToken.getCSRFToken() );

  24:     if( !ldap->authenticateLdapUser(in->getUserName(), password)) {

  25:         LogDebug( kFuncName.c_str(), "LDAPBadPassword" );

  26:         out->setStatus( SignInStatus::BadPassword );

  27:         return out;

  28:     }        

  29:     out->setStatus( SignInStatus::Success );

  30:     LogDebug( kFuncName.c_str(), "Success" );

  31:     return out;

  32: }

Challenge IV – IsDifferent

This is a slightly modified version of last year’s “IsDifferent” challenge, mostly it’s the same thing, but if it’s new to you, it’s still new.

I’m embarrassed to say that at the conference, we briefly had a bug in our own code. That bug has been corrected below.

   1: bool isDifferent(

   2:     SomeClass const * newObject,

   3:     SomeClass const * oldObject) const

   4: {

   5:     // Returns true if newObject is different from oldObject.

   6:  

   7:     // Shortcut if same pointer.

   8:     return newObject != oldObject &&

   9:  

  10:     // Protect equals from being called on NULL.

  11:         newObject != 0 &&

  12:  

  13:     // Return the result of "equals"

  14:         ! newObject->equals(oldObject);

  15: }

Challenge V – MultithreadRun

This was perhaps the one with the most extraneous flaws in it.

Yes, the cmd could be altered between the “is_user_admin” check and the cmd_copy line. That might happen, but the WRITE and DELETE commands still would be disallowed if the user is not an admin. Maybe this code operates in an environment where it’s safe for this to happen – perhaps admins only call WRITE or DELETE, and maybe WRITE and DELETE only execute queued operations that have already been approved and are merely waiting for an admin to choose the right time. OK, that’s a stretch, but the hint here is that this is NOT the bug we are looking for.

So, what is the bug we are looking for? Ask more questions, and I’ll answer them here – but of course, I won’t post the answer to any of these code challenges for a few weeks.

   1: #define READ      1

   2: #define WRITE     2

   3: #define DELETE    3

   4:  

   5: int cmd;

   6:  

   7: void multithread_update_cmd(int new_cmd)

   8: {

   9:     cmd = new_cmd;

  10: }

  11:  

  12: int multithread_run(USERCONTEXT *pContext, CMDCONTEXT *pCmd)

  13: {

  14:     bool admin = is_user_admin(pContext);

  15:     // Copy the command so as to prevent it being altered

  16:     // by another thread.

  17:     int cmd_copy = cmd;

  18:  

  19:     // Only admins can perform writes and deletes

  20:     if(!admin && (cmd_copy == WRITE || cmd_copy == DELETE))

  21:         return -1;

  22:  

  23:     switch(cmd_copy)

  24:     {

  25:     case READ:

  26:         perform_read(pCmd);

  27:         break;

  28:     case WRITE:

  29:         perform_write(pCmd);

  30:         break;

  31:     case DELETE:

  32:         perform_delete(pCmd);

  33:         break;

  34:     default:

  35:         return -1;

  36:  

  37:     }

  38:  

  39:     return 0;

  40: }

Black Hat with Amazon.com–2011 Code Challenges I

As a part of my day job at Amazon, I get to spend time recruiting the brightest and the best of the world’s security professionals – especially those who are willing to move to Seattle, Virginia, Dublin or Bangalore. Every so often, we go out on the road to security conferences, and as well as being able to learn from other security professionals who are presenting, we have a booth whose chief purpose (aside from the usual networking) is to recruit security staff.

If you are interested in security jobs at Amazon, visit http://security.amazon-jobs.com to see what’s available, and email security-ninjas@amazon.com to express your interest and submit your resume.

Black Hat 2011

We’re part way through the first day here at Black Hat in Las Vegas, and already the coding challenge is generating a lot of interest. Every morning, and every afternoon, we put up a piece of code – it’s a small piece of code, to make it readable and to make solving the challenge relatively quick and simple. But there’s something wrong with the code.

In my favourite samples, the flaw is a security flaw, but sometimes the flaw is something that, while not directly security related, may still cause a bug to trigger incorrect security behaviour.

Inevitably, we take down the coding challenge before some of the attendees have had a chance to read and work with it. Also, there is no way for non-attendees to get access to the code on the easel.

To fix that, I am uploading the code samples here to my blog. It’s important for readers to know that this is not an indication that anything in this blog is sanctioned or approved by Amazon.com, and it is not an indication that I speak for Amazon.com in any way whatsoever.

Having got that disclaimer out of the way, here’s the code we submitted for today, August 3rd, 2011.

Morning code sample: PerlForm

#!/opt/third-party/bin/perl –w
use strict;
use CGI qw/:standard/;
my $cgi = CGI->new;
my $name = $cgi->param("name");
my $item = $cgi->param("item");
my $count = $cgi->param("count");
print $cgi->header;
print $cgi->start_html('Form test code');
print $cgi->start_form;
print 'Name:',$cgi->textfield("name",$name),$cgi->br;
print 'Item:',$cgi->textfield("item",$item),$cgi->br;
print 'Count:',$cgi->textfield("count", $count),$cgi->br;
if (! $cgi->param) {
    # No values - show submit button
    print $cgi->submit;
    # CSRF protection - submit hidden nonce
    my $nonce = rand(100000000); # A bazillionty.
    print $cgi->hidden("nonce-value",$nonce);
} else {
    # Values - purchase item. Use cookie to identify session
    process_values($name, $item, $count);
}
print $cgi->end_form;
print $cgi->end_html;
exit 0;

Afternoon code sample: FixedPoint

bool fixedPoint(int nDecimals, const char *str, int &out)
{
// Converts string representation of decimal numbers
// to fixed-point integer representation, multiplying
// by 10 ^ nDecimals.
// Input has been sanitised and is trusted to be valid.

    char *point = 0, *end = 0;
    int frac = 0, digits = 0;

    out = strtol(str, &point, 10);

    if ( *point == '.' )
    {
        frac = strtol(point+1, &end, 10);
        digits = end-point-1;
    } else if (point == str)
        return false;

    while (nDecimals—)
    {
        out *= 10;
        if ( --digits == 0 )
            out += frac;
    }

    return true;

}

Note that the comments here can be relied upon. When we say that the inputs are sanitised and can be trusted to be correct, that means that nDecimals is always greater than or equal to the number of digits past the decimal point. strtol starts at the first parameter converting a representation of an integer from character to integer, and when it finds a character not part of that integer representation, it stops, and stores the pointer to that invalid character in the second parameter. The third parameter is a base, or radix. Here, we use base 10. There is no integer overflow going on here, the numbers being passed in are relatively small.

So what are we doing here?

Obviously, I’m not going to provide answers here for some time, because that would reduce the

2ndAuth released for Windows 7, Windows Server 2008 R2

I’ve given some hints at what we’ve been working on lately, by my choice of article topics.

Credential Providers have been my headache for a couple of months now, not least of which is because Microsoft haven’t quite provided all the working code they ought to have done for Windows Vista. Windows 7, now that works just fine. So that’s what we’re supporting – Windows 7 and Windows Server 2008 R2 (essentially Windows 7 Server) – with our new release of 2ndAuth.

[We’re still supporting 2ndAuth for Windows Server 2003 / Windows XP / Windows 2000, and will be releasing patches, new features and updates as necessary]

To whet your appetite, here’s a screen-shot of 2ndAuth at work on a Windows 7 system:

2ndAuth7

Notice that when 2ndAuth detects that you’ve selected to log on to a shared user (by a confusing coincidence, this one has a first name of “Shared”, and a last name of “User”), it prompts you for a second authentication (hence the name), which requires that the actual user enter another set of credentials (these should be their own credentials, and shared users cannot vouch for other shared users). This is then written to the Windows Event Log so that you can check who has been accessing which shared accounts and when.

Unauthenticated / failed attempts are also logged, but it’s difficult to say how useful it is to read that, since the failure could be with an invalid user name as much as an invalid password.

Terminal Services / Remote Desktop Connections are supported, too, as well as locking and unlocking the workstation (e.g. handing off to another user part way through a procedure).

The goal here is to acknowledge that sometimes you can’t help using a shared account, and the best thing to do is to provide a mechanism whereby you can discover who is responsible for the use of that account.

I’ll be adding a download link to our products page for 2ndAuth in a little while, but in the meantime, please feel free to ask me any questions about this service – either in the blog comments here, or by email to alun@texis.com.

Command Line MD5 hash

A colleague asked me the other day what the command-line tool was for calculating MD5 hashes in Windows.

In a moment of sanity, I told him that the usual tool was FCIV, the Microsoft File Checksum Integrity Verifier, but that you had to download it.

Then when he started making fun, and saying that Linux had a command-line tool built in, I went more towards insanity, and suggested the following for him:

[BitConverter]::ToString((new-object Security.Cryptography.MD5CryptoServiceProvider).ComputeHash((new-object IO.FileInfo("c:\windows\explorer.exe")).OpenRead())).Replace("-","").ToLower()

Sure, it’s PowerShell, but that’s been a part of Windows for some while now.

[If you really want to use the example, note that it calculates the hash for the file c:\windows\explorer.exe – change the string to change the file.]

More useful is to create a function:

function MD5 ($a) {[BitConverter]::ToString((new-object Security.Cryptography.MD5CryptoServiceProvider).ComputeHash((new-object IO.FileInfo($a)).OpenRead())).Replace("-","").ToLower();}

Then you can call this with MD5(“c:\windows\calc.exe”) to get a hash of the Calculator.

The meta-lesson

But this does draw out a distinction between operating systems – Linux has an MD5 hash calculator because you are expected to calculate MD5 hashes of files manually on a regular basis. Windows doesn’t have an MD5 hash calculator, because that’s generally done for you. Windows Update will check hashes on files it downloads before it applies them, for instance.

You can learn a lot about an operating system by looking at what is in its default deployment, and what is absent – and why it’s absent (which you can deduce from finding out what you’re supposed to do instead).

The power of stupidity

I just spent a couple of days trying to figure out why logon-related code that worked in Windows XP failed in Windows Vista and Windows 7.

hToken = NULL;
if ( LogonUser( g_sUser, bIsUPN ? NULL : g_sDomain, g_sPass, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, &hToken ) )
{
    // Re-populate the g_sUser and g_sDomain values from the token!
    TOKEN_USER tUser;
    DWORD nLength;
    // Get the user / domain information from the token.
    if (GetTokenInformation(hToken,TokenUser,&tUser,sizeof tUser,&nLength))
    {
        SID_NAME_USE eUse;
        DWORD dwUserSize = _countof(g_sUser);
        DWORD dwDomainSize = _countof(g_sDomain);
        LookupAccountSid(NULL,&tUser.User.Sid,
            g_sUser, &dwUserSize,
            g_sDomain, &dwDomainSize,
            &eUse);
    }
    CloseHandle(hToken);
}

[Note that some error handling has been removed for clarity and brevity.]

So what was going wrong? This totally used to work – it’s designed to validate the username and password, as well as to provide me with the canonical form of the user name.

I had a look through the APIs, and sure enough, there was a more up-to-date version of one of them – LogonUser has a colleague, LogonUserEx, and that function returns the Logon SID as well as verifying the logon works. Cool, I thought, I can get rid of GetTokenInformation, which seems to be failing anyway, and use LogonUserEx.

No dice.

LogonUserEx claimed to be working, and yet LookupAccountSid returned an error, signifying ERROR_NONE_MAPPED (1332 decimal, 0x534 in hex, “No mapping between account names and security IDs was done.”)

A little searching on ERROR_NONE_MAPPED led to a blog post by David LeBlanc, indicating that logon SIDs will cause this error, because they are entirely ephemeral SIDs, used mainly to protect securable items that should not be available to processes running outside of this logon session (and, by the same measure, allowing access to be provided, where appropriate, across different processes in the same logon session).

And then I realised, after a few hours of experimentation, the answer was staring me in the face, in the documentation – LogonUserEx returns the Logon SID in ppLogonSid, which is a Logon SID. Does not have a name, only a SID.

So, that explained the failure of LookupAccountSid with LogonUserEx, and I returned to using LogonUser – which left me with the conundrum of what was failing there.

It often turns out to be the simplest of things.

TOKEN_USER is a structure containing a pointer to the SID. As such, GetTokenInformation has to put the SID somewhere. Cleverly, it asks you to build your TOKEN_USER structure a little bit long, and places the SID at the end of the structure, before setting the pointer in the structure to point to the SID. So, sizeof(TOKEN_USER) is not big enough to pass to a GetTokenInformation call requesting a TokenUser.

The big question is, not why this failed, but why it worked ever at all! I’m not too fussed in finding that answer, because I’ve now changed my code to do it properly, and everything still works – on Windows Vista and XP. But I do feel stupid that debugging this code took me part of Sunday and a little of Monday evening.

Now the code looks like this (again, some error handling has been removed for brevity – don’t skimp in your production code!)

hToken = NULL;
if ( LogonUser( g_sUser, bIsUPN ? NULL : g_sDomain, g_sPass, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, &hToken ) )
{
    SecureZeroMemory(g_sPass,sizeof g_sPass);
    TOKEN_USER *ptUser;
    DWORD nLength;
    GetTokenInformation(hToken, TokenUser, NULL, 0, &nLength);
    ptUser = (TOKEN_USER*)new char[nLength];
    // Get the user / domain information from the token.
    if (GetTokenInformation(hToken,TokenUser,ptUser,nLength,&nLength))
    {
        SID_NAME_USE eUse;
        DWORD dwUserSize = _countof(g_sUser);
        DWORD dwDomainSize = _countof(g_sDomain);
        LookupAccountSid(NULL,ptUser->User.Sid,
            g_sUser, &dwUserSize,
            g_sDomain, &dwDomainSize,
            &eUse);
    }
    delete [] (char *)ptUser;
    CloseHandle(hToken);
}

Note that the fix is to request the length of the TOKEN_USER structure with an initial call to GetTokenInformation, followed by a second call to fill it in.

Starting to build your own Credential Provider

If you’re starting to work on a Credential Provider (CredProv or CP, for short) for Windows Vista, Windows Server 2008, Windows Server 2008 R2 or Windows 7, there are a few steps I would strongly recommend you take, because it will make life easier for you.

0. Read Dan Griffin’s article in MSDN Magazine.

The article, "Create Custom Login Experiences With Credential Providers For Windows Vista" by Dan Griffin in January 2007’s MSDN Magazine on Credential Providers is a truly excellent source of information, gleaned largely by the same exhaustive trial and error effort that you will be engaging in with your own CP.

0.1 Read it again.

0.2 And again, and again and again.

As you work on your CP, you will keep running into questions and new insights as to what it is that Dan was telling you in that article.

Keep a printed copy next to you when developing your CP, so that you can keep looking back to it.

If you have met Dan and asked his permission, keep him on speed-dial.

1. Test your Credential Provider in a Virtual PC environment.

You will screw something up, and when you do, the logon screen will most likely cycle over and over and over (what, Microsoft couldn’t provide a “this Credential Provider has failed eighteen times in a row and will be temporarily disabled” feature?), preventing you from logging back on to change out your broken CP. At this point, you really want to revert back to a previous working session.

To my mind, the easiest way to do this is to create one Virtual PC environment with a base Windows 7 system, patched up to current levels, and with a few test users installed. You can burn an MSDN licence up on this test installation, if you like, but quite frankly, I’m likely to want to refresh it from scratch every so often anyway, so the activation timeout is no big deal.

Once you have created this base image, create another virtual machine, based off the virtual hard disk (VHD) of the base image, and be sure to enable undo disks. This way, when things go wrong, you can shut down this second virtual machine, telling Virtual PC to discard the Undo Disk data, and you will be able to restart the machine immediately and continue to work on it.

2. Enable the kernel debugger against your VM.

This is a little tricky.

2.1 First, edit the settings on your VM.

Enable COM1 to point to a Named Pipe, such as “\\.\pipe\credprov”:

SNAGHTML32948a2f

2.2 Now, enable kernel debugging on the VM itself

Log on to the VM, and use the bcdedit tool, from an Administrator Command Prompt to change the debugging option in the boot database. You can go the long way around, reading Microsoft’s instructions on how to do this, or you can simply use the following two commands:

bcdedit /dbgsettings serial debugport:1

bcdedit /debug {current} on

SNAGHTML32af8687

Notice that Microsoft suggests creating a separate environment for debugging on and off, but I don’t see that as being terribly useful. I will always be debugging this test environment, and it really doesn’t slow me down that much. You can always use “bcdedit /debug {current} off” to turn debugging off later.

This setting will take effect at the next reboot of the VM, but don’t reboot yet.

2.3 Enable the Debug Output Filter so OutputDebugString works.

Windows Vista and later don’t output debug messages to the kernel debugger by default. Those messages are filtered. You can spend a lot of time trying to figure out why you are staring at a blank screen when you have filled your code with OutputDebugString and/or TRACE calls. Or you can change the registry entry that controls the Output Debug Filter:

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Debug Print Filter\DEFAULT

Create the “Debug Print Filter” value, if it isn’t there, and then create the DEFAULT value as a DWORD, and set it to the value 8.

image

2.4 Save these settings

Since you’ll want these settings to come back after a restart, you’ll want to commit them to the VHD. Easily done, but takes some time. Shut down the VM, and when you are prompted what you want to do, select that you wish to commit changes to the virtual hard disk.

SNAGHTML32b6c635[4]

Expect this to take several long minutes. While you do that, go read Dan’s article again.

2.5 Create a shortcut to the debugger

I use WinDBG (is that pronounced “Windbag”?), and the shortcut I use points to:

"C:\Program Files\Debugging Tools for Windows (x64)\windbg.exe" -k com:port=\\.\pipe\credprov,baud=115200,pipe,reconnect,resets=10

Remember to start the VM before starting the WinDBG shortcut, so that the VM has a pipe for WinDbg to connect to.

3. Start from the CredProv samples

Play around with the credential provider sample, or samples, that are closest to your eventual design goal, and add features to move them towards your desired end-state, rather than building your own from scratch.

Don’t just play with the one sample – looking at, or testing, the other samples may give you a little more insight that you didn’t get from the sample you’re working with.

3.1 Build often, and test frequently

Random errors and occasional misunderstandings (“gee, I didn’t realise you can’t call SetFieldString from GetStringValue”) will cause you to crash often. A crash in your CP means an infinite loop, and some inventive use of Anglo-Saxon.

Building often, testing frequently, and backing out disastrous changes (use version control if you have it!) will lead to a better process.

3.2 Later, build your own CP

Once you have a good understanding of the Credential Provider and its mysterious ways, you may decide to throw out Microsoft’s code and build your own from scratch. Keep comparing against your modified sample to see why it isn’t working.

3.3 Before deployment, change the GUID!

The GUIDs used by the sample code are well-known, and will tie in some systems to other, more shoddy, developers’ versions of those samples. If you forget to change the GUID on your code, you will have a CP-fight.

4. Go back to Dan’s article every time you reach a bottleneck

Occasionally a twist of phrase, or a reinterpretation of a paragraph is all it takes to wring some more useful knowledge out of this article. Don’t forget to use the online help Microsoft provides, as well as searching the MSDN, but remember that this is not a very frequently-trod path. It may be that you are doing something the credential provider architects didn’t consider. In fact, it’s highly likely.

5. Stop mailing credprov@microsoft.com

Nobody monitors that email address any more, and there seems to be something of a black hole associated with questions related to Credential Providers in general. It’s as if nobody really truly understands them. A few of the MVPs (particularly Dan Griffin, Dana Epp, and perhaps myself) have a good understanding, so read their blogs, and perhaps post to the Microsoft Forums, if you can manage to do so.

6. Enumerate, and test, the scenarios your customers might run into

  • domain-joined and non-domain
  • administrator, non-administrator, guest
  • with and without user names being supplied (Secpol.msc –> Local Policies –> Security Options –> Interactive Logon: Do not display last user name)
  • default domain, other domain, local accounts
  • logon, switch user, unlock workstation, access from Remote Desktop Connection / MSTSC (as we old-timers call it)
  • change password
  • If you’re of a mind, test the credential user interface mode, too.

Vulnerability Disclosure–Cheap, Fast, and Out of Control?

I’ve posted a few times before on vulnerability disclosure:

As you can tell from the titles (I’m not vain enough to think you actually clicked and read any of those), my stance is that public disclosure without vendor (or developer, if you prefer, because not everyone charges for the software they distribute) involvement benefits only the discloser and the criminal hackers who want to download unfixed exploits (zero days). I also agree with Microsoft’s stance that “responsible disclosure” is a term that means only whatever the author wants it to mean at the time he writes it, and that “coordinated disclosure” more accurately reflects the goal of having discoverer work with developer / vendor to provide the best security result, of having a fix or workaround shipped as soon as possible, and with the best chance of it arriving before malicious exploits.

Vulnerability Databases – not helping

The various vulnerability databases that are used by discoverers when publicising their vulnerabilities certainly don’t help the situation.

First, of course, is the word “various”. That there are several vulnerability databases out there is a classic problem – it is inefficient in the extreme for vendors to read them all, and filter out the duplicates to find only those issues that are unique and new.

Then there’s the reverse angle on “vendors can’t realistically devote the time to read through the multitude of vulnerability databases” – certainly the vulnerability database authors don’t read the vendors’ statements, because each database is littered with reports marked as “unpatched” that have been patched for years. I keep finding new database entries relating to “unpatched” bugs in my own software that were actually fixed several releases – and several years – ago.

It would be rather handy if these databases would communicate with vendors when they are adding an exploit to their database, so that the vendor could respond right back when the issue is fixed. Perhaps what is needed is a filtered feed protocol of some kind, so that a vendor could “subscribe” their applications (perhaps even with version numbers), and could then work off the exploits as they are recorded, assigning them either as “duplicates”, or to a new bin, and thereby automatically send out notices to the vulnerability databases when the flaws are fixed, along with information on how to get the fixes.

Each time I have suggested this, the reception I get back has been rather frosty – as if the vulnerability database owners are happy with the status quo. Since their business model is based on alarming users about their security posture, perhaps that’s not too far from the truth.

Finally, there’s an apparent lack of oversight at many of these vulnerability databases of the vulnerabilities and exploits submitted. “They’ll let anything through” is the sentiment I’ve heard from many of my colleagues in the security world, echoing my own opinion.

Discoverers – get your act together!

Along with the “let anything through”, of course, is the issue of discoverers submitting any old thing, because they know they’ll see their name in (virtual) print. While I can understand the thrill (I do have a blog, after all), I also think that there needs to be a certain level of community involvement which will say “try harder and come back when you have a big-boy post for us”. This is partly the vulnerability database handlers’ fault, but also it’s the fault of the community of discoverers, which seems to be uninterested in the idea of ensuring that the community around them is of high quality. Where’s the dissent? Where are the people asking for better reports, more convincing examples?

Here’s my example

As you can imagine, I had to have my own “tipping point” that made me write this post. That point was when I dealt with the report at http://www.exploit-db.com/exploits/12587/ – “WFTPD Server 3.30 Multiple remote vulnerabilities(0day)”, discovered by “fl0 fl0w”. Notice that I didn’t actually receive an email directing me to this vulnerability – discoverer and multiple vulnerability databases simply publicise it without bothering to verify with me that this is a real vulnerability, or to give me a chance to help correct it if it is. Exploit-db, like others, even goes so far as to mark it with a “verified” check mark, so that you know it’s a top-notch vulnerability, really bad stuff.

That title seems like a winner – MULTIPLE REMOTE VULNERABILITIES, and a zero-day, no less. Great, scary stuff, worthy of a reading in Vincent Price’s voice.

Now, let’s have a look at the descriptive text.

Oh, that’s right, there isn’t any – it’s all source code. No problem, I’m a developer, and it’s written in a language I speak.

Fine, so I read the source code, and all I can tell that it does is connect to an FTP server (presumably running WFTPD) at a user-provided address, where it uses a user-provided username and password, to log on. Then it sends the SYST command (presumably so you can verify the information returned), and finally runs either the MKD or DELE command, with user-supplied parameters to make a directory, or delete a file.

So far, all he’s got is a minimalist FTP client, rather than a piece of code specifically displaying a flaw. I could get his code to do a number of things, such as, well, making a directory, and deleting a file.

The comments in the file did suggest that there’s something important about “../” and “../../”, so there’s a hint there of a directory traversal flaw, or “directory transversal” as “fl0 fl0w” puts it.

So, I spend a few hours trying a variety of different traversal attack possibilities, each time coming up empty. Of course, this could simply be due to the old security maxim that of course you can design a security mechanism that you can’t break. The tough part is finding a security mechanism that other people can’t break.

Finally, I manage to find “fl0 flow” – apparently, he goes by “flo_flow_supremacy@yahoo.com”, as well as the more pedestrian “Stefan M”. A series of email exchanges finally makes it clear what his alleged “multiple remote vulnerabilities” are:

Well maybe it is a problem of validation/sanitization of user-supplied input in the commands: MKD and DELE because when used like so : expl.exe -h hostname -u user -w passwd -p port(21) -o 1 ../../folderName, you can delete folders, or used with -o 2 you can make folders up 2 dirs for this example. The server is acting like it is supposed to just that you can traverse directories using those 2 commands followed by this syntax ../../../../../.
I hope it helps ,all the best

Thankfully, he is at least polite – I’ve done this sort of dance on more than one occasion with discoverers who are not only wrong, but also rude and aggressive with it.

Surely I’ve misunderstood Flo’s point, because it doesn’t sound like “the server is acting like it is supposed to” matches the term “multiple remote vulnerabilities” – so I ask him point-blank:

For this to be an exploit, it would have to demonstrate that you are able to delete a file, or create a directory, in a location to which you have no rights at all [to do that]. Is this what you are saying?

It sounds like you are saying only that “../” is a bad thing to accept, and that I dispute – relative directories are perfectly acceptable, except where they allow you to exceed your rights and avoid a check on permissions.

In response, Flo tells me:

well basicly yea that’s what I meant and I respect your argument.
     Let me know if there is something else ,I’m sorry for the confusion.
     All the best,

All this, and the tag-line of “Multiple Remote Vulnerabilities (0Day)” spread around the Internet on my server, just because Stefan doesn’t like a server that accepts “..” – I’m sure you’ll understand that this isn’t a behaviour I’m going to change.

“..” is a natural part of paths on Windows and Linux, and it’s a natural part of FTP virtual file systems. The mere act of accepting it is only a directory traversal vulnerability if you can use it to access files and folders to which you should not have access. Neither Flo nor I can find a way to do that outside of the security protection systems in WFTPD and WFTPD Pro.

Does this mean he will retract his claim of a vulnerability? No.

Does this mean that the vulnerability databases will be removing this vulnerability? Apparently not that, either.

So, now someone researching my software finds an “unpatched vulnerability” that never actually existed.