Writing Secure Code Vista

Download as pdf or txt
Download as pdf or txt
You are on page 1of 222
At a glance
Powered by AI
The document discusses license terms for using an eBook from Microsoft. It covers installation and use rights, scope of license, entire agreement, applicable law, legal effect, disclaimer of warranty, and limitation on remedies and damages.

The license terms allow one user to install one copy on a computer and an additional copy on a portable device. They restrict copying, distributing, modifying, or combining the content with other works in an unauthorized manner.

The license terms restrict copying the content, distributing or sharing it, modifying or adapting it, reverse engineering or decompiling it, and using it for anything other than personal use.

MICROSOFT LICENSE TERMS

MICROSOFT EBOOK
These license terms are an agreement between Microsoft Corporation (or
based on where you live, one of its affiliates) and you. Please read them.
They apply to the licensed content named above, which includes the media
on which you received it, if any.
By using the licensed content, you accept these terms. If you do not accept
them, do not use the licensed content.
If you comply with these license terms, you have the rights below.

1. OVERVIEW.
Licensed Content. The licensed content includes the eBook and associated
media.
License Model. The licensed content is licensed on a per user per device basis.

2. INSTALLATION AND USE RIGHTS.


a. General. One user may install and use one copy of the licensed content on
a single computer.
b. Portable Device. You may install an additional copy of the licensed content
on a portable device for the exclusive use of the primary user of the first copy
of the licensed content.
3. SCOPE OF LICENSE. The licensed content is licensed, not sold. This agreement
only gives you some rights to use the licensed content. Microsoft reserves all
other rights. Unless applicable law gives you more rights despite this limitation,
you may use the licensed content only as expressly permitted in this agreement.
You agree

Not to make copies of the licensed content;

Not to distribute, rent, lease, lend, reproduce, transit, adapt, modify, link to,
post, forward, make derivative works based upon, disseminate, publish or
sublicense the licensed content or combine the licensed content with other
third party content, or otherwise use the licensed content in an unauthorized
or illegal manner;

Not to permit any third-party to access, copy or download the licensed


content;

Not to reverse engineer, decompile, remove or otherwise thwart any


protections or disassemble the licensed content except as otherwise
specifically permitted by applicable law;

Circumvention of the measures taken to protect the rights in the licensed


content or otherwise facilitating an infringement of copyright is strictly
prohibited;

To keep the licensed content in the same format in which it was provided;
and

To use the licensed content solely for your personal use.

4. ENTIRE AGREEMENT. This agreement is the entire agreement for the licensed
content.
5. APPLICABLE LAW.
a. United States. If you acquired the licensed content in the United States,
Washington state law governs the interpretation of this agreement and
applies to claims for breach of it, regardless of conflict of laws principles. The
laws of the state where you live govern all other claims, including claims
under state consumer protection laws, unfair competition laws, and in tort.
b. Outside the United States. If you acquired the licensed content in any
other country, the laws of that country apply.
6. LEGAL EFFECT. This agreement describes certain legal rights. You may have
other rights under the laws of your country. You may also have rights with
respect to the party from whom you acquired the licensed content. This
agreement does not change your rights under the laws of your country if the laws
of your country do not permit it to do so.
7. DISCLAIMER OF WARRANTY. THE LICENSED CONTENT IS LICENSED
AS-IS. YOU BEAR THE RISK OF USING IT. MICROSOFT GIVES NO
EXPRESS WARRANTIES, GUARANTEES OR CONDITIONS. YOU MAY
HAVE ADDITIONAL CONSUMER RIGHTS UNDER YOUR LOCAL LAWS
WHICH THIS AGREEMENT CANNOT CHANGE. TO THE EXTENT
PERMITTED UNDER YOUR LOCAL LAWS, MICROSOFT EXCLUDES THE
IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NON-INFRINGEMENT.
8. LIMITATION ON AND EXCLUSION OF REMEDIES AND DAMAGES. YOU
CAN RECOVER FROM MICROSOFT AND ITS SUPPLIERS ONLY DIRECT
DAMAGES UP TO U.S. $5.00. YOU CANNOT RECOVER ANY OTHER
DAMAGES, INCLUDING CONSEQUENTIAL, LOST PROFITS, SPECIAL,
INDIRECT OR INCIDENTAL DAMAGES.

This limitation applies to

anything related to the licensed content, software, services, content


(including code) on third party Internet sites, or third party programs; and

claims for breach of contract, breach of warranty, guarantee or condition,


strict liability, negligence, or other tort to the extent permitted by applicable
law.

It also applies even if Microsoft knew or should have known about the possibility of
the damages. Some states do not allow the exclusion or limitation of incidental or
consequential damages, so the above limitation or exclusion may not apply to you.
They also may not apply to you because your country may not allow the exclusion or
limitation of incidental, consequential or other damages.
Please note: As this licensed content is distributed in Quebec, Canada, some
of the clauses in this agreement are provided below in French.
Remarque : Ce le contenu sous licence tant distribu au Qubec, Canada,
certaines des clauses dans ce contrat sont fournies ci-dessous en franais.
EXONRATION DE GARANTIE. Le contenu sous licence vis par une licence est
offert tel quel . Toute utilisation de ce contenu sous licence est votre seule risque
et pril. Microsoft naccorde aucune autre garantie expresse. Vous pouvez bnficier
de droits additionnels en vertu du droit local sur la protection dues consommateurs,
que ce contrat ne peut modifier. La ou elles sont permises par le droit locale, les
garanties implicites de qualit marchande, dadquation un usage particulier et
dabsence de contrefaon sont exclues.
LIMITATION DES DOMMAGES-INTRTS ET EXCLUSION DE
RESPONSABILIT POUR LES DOMMAGES. Vous pouvez obtenir de Microsoft et
de ses fournisseurs une indemnisation en cas de dommages directs uniquement
hauteur de 5,00 $ US. Vous ne pouvez prtendre aucune indemnisation pour les
autres dommages, y compris les dommages spciaux, indirects ou accessoires et
pertes de bnfices.
Cette limitation concerne:

tout ce qui est reli au le contenu sous licence, aux services ou au contenu (y
compris le code) figurant sur des sites Internet tiers ou dans des programmes tiers ;
et

les rclamations au titre de violation de contrat ou de garantie, ou au titre de


responsabilit stricte, de ngligence ou dune autre faute dans la limite autorise par
la loi en vigueur.
Elle sapplique galement, mme si Microsoft connaissait ou devrait connatre
lventualit dun tel dommage. Si votre pays nautorise pas lexclusion ou la limitation

de responsabilit pour les dommages indirects, accessoires ou de quelque nature que


ce soit, il se peut que la limitation ou lexclusion ci-dessus ne sappliquera pas votre
gard.
EFFET JURIDIQUE. Le prsent contrat dcrit certains droits juridiques. Vous
pourriez avoir dautres droits prvus par les lois de votre pays. Le prsent contrat ne
modifie pas les droits que vous confrent les lois de votre pays si celles-ci ne le
permettent pas.

PUBLISHED BY
Microsoft Press
A Division of Microsoft Corporation
One Microsoft Way
Redmond, Washington 98052-6399
Copyright 2007 by David LeBlanc and Michael Howard
All rights reserved. No part of the contents of this book may be reproduced or transmitted in any form
or by any means without the written permission of the publisher.
Library of Congress Control Number: 2007922582
Printed and bound in the United States of America.
1 2 3 4 5 6 7 8 9 QWT 2 1 0 9 8 7
Distributed in Canada by H.B. Fenn and Company Ltd.
A CIP catalogue record for this book is available from the British Library.
Microsoft Press books are available through booksellers and distributors worldwide. For further information about international editions, contact your local Microsoft Corporation office or contact Microsoft
Press International directly at fax (425) 936-7329. Visit our Web site at www.microsoft.com/mspress.
Send comments to [email protected].
Microsoft, Microsoft Press, Active Directory, ActiveX, Authenticode, BitLocker, Hotmail, Internet
Explorer, MSDN, Outlook, SQL Server, Visual Basic, Visual C++, Visual Studio, Win32, Windows,
Windows CardSpace, Windows Media, Windows NT, Windows Server, and Windows Vista are either
registered trademarks or trademarks of Microsoft Corporation in the United States and/or other countries.
Other product and company names mentioned herein may be the trademarks of their respective owners.
The example companies, organizations, products, domain names, e-mail addresses, logos, people, places,
and events depicted herein are fictitious. No association with any real company, organization, product,
domain name, e-mail address, logo, person, place, or event is intended or should be inferred.
This book expresses the authors views and opinions. The information contained in this book is provided
without any express, statutory, or implied warranties. Neither the authors, Microsoft Corporation, nor its
resellers, or distributors will be held liable for any damages caused or alleged to be caused either directly
or indirectly by this book.
Acquisitions Editor: Ben Ryan
Developmental Editor: Devon Musgrave
Project Editor: Valerie Woolley
Editorial and Production Services: Carlisle Publishing Services
Body Part No. X13-62470

For Web Developers


Microsoft ASP.NET 3.5
Step by Step

Programming Microsoft
ASP.NET 3.5

George Shepherd

Dino Esposito

ISBN 9780735624269

ISBN 9780735625273

Teach yourself ASP.NET 3.5one step at a time. Ideal


for developers with fundamental programming skills
but new to ASP.NET, this practical tutorial delivers
hands-on guidance for developing Web applications
in the Microsoft Visual Studio 2008 environment.

The definitive guide to ASP.NET 3.5. Led by well-known


ASP.NET expert Dino Esposito, youll delve into the
core topics for creating innovative Web applications,
including Dynamic Data; LINQ; state, application, and
session management; Web forms and requests; security
strategies; AJAX; Silverlight; and more.

JavaScript
Step by Step

Microsoft Visual Web


Developer 2008
Express Edition
Step by Step

Steve Suehring
ISBN 9780735624498

Eric Griffin
ISBN 9780735626065
Your hands guide to learning fundamental Webdevelopment skills. This tutorial steps you through
an end-to-end example, helping build essential skills
logically and sequentially. By the end of the book, youll
have a working Web site, plus the fundamental skills
needed for the next levelASP.NET.

Build on your fundamental programming skills, and get


hands-on guidance for creating Web applications with
JavaScript. Learn to work with the six JavaScript data
types, the Document Object Model, Web forms, CSS
styles, AJAX, and other essentialsone step at a time.

Programming Microsoft LINQ

Introducing Microsoft
Silverlight 2,
Second Edition

Paolo Pialorsi and Marco Russo


ISBN 9780735624009

Laurence Moroney
ISBN 9780735625280

Get a head start with Silverlight 2the cross-platform,


cross-browser plug-in for rich interactive applications
and the next-generation user experience. Featuring
advance insights from inside the Silverlight team, this
book delivers the practical, approachable guidance and
code to inspire your next solutions.

With LINQ, you can query datano matter what the


sourcedirectly from Microsoft Visual Basic or C#.
Guided by two data-access experts whove worked with
LINQ in depth, youll learn how Microsoft .NET Framework
3.5 implements LINQ, and how to exploit it. Study and
adapt the books examples for faster, leaner code.

ALSO SEE
Developing Service-Oriented AJAX
Applications on the Microsoft Platform
ISBN 9780735625914

Programming Microsoft ASP.NET 2.0


ISBN 9780735625273

Microsoft ASP.NET 2.0 Step by Step

Programming Microsoft ASP.NET 2.0


Applications: Advanced Topics

ISBN 9780735622012

ISBN 9780735621770

microsoft.com/mspress

For my mother and father. Thank you for encouraging me in my earliest geeky
endeavors. For buying my first chemistry set, microscope and rock collection.
But most of all, I cant express how much I appreciate you
getting me my very first computer.
Michael

To my wife, Jennifer, who has put up with yet another book. To Mr. Pennington, our school librarian,
who I set out to annoy by programming a noisy computer in his library Ive been hooked on
programming since. To Floyd R. Hacker, who introduced me to Windows,
and one fateful day took a huge pile of research data, pulled it
into Excel and quite unknowingly set me along this path.
David

iii

A04C623934.fm Page v Thursday, March 15, 2007 1:17 PM

Contents at a Glance
1
2
3
4
5
6
7
8
9

Code Quality . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
User Account Control, Tokens, and Integrity Levels . . . . . . . . . . . . . . .
Buffer Overrun Defenses . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Networking Defenses . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Creating Secure and Resilient Services . . . . . . . . . . . . . . . . . . . . . . . . . .
Internet Explorer 7 Defenses . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Cryptographic Enhancements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Authentication and Authorization . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Miscellaneous Defenses and Security-Related Technologies . . . . . . .

1
13
49
75
97
121
135
151
163

Table of Contents
Foreword . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xiii
Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xvii
Target audience . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xviii
How does this book relate to Writing Secure Code?. . . . . . . . . . . . . . . . . . . . . . . . . xviii
How to Read This Book . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xix
Getting Started with the Code in this Book . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xx
Whats on the Companion Web Site? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xxi
System Requirements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xxi
Microsoft Press Support . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xxii
Questions and Comments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xxii

Code Quality . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

The Windows Vista Quality Gates . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

All C/C++ String Buffers Annotated with SAL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

SAL by Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

__in . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

__out. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

__in_opt . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

__inout . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

__inout_bcount_full(n) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

__inout_bcount_part(n,m) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

__deref_out_bcount(n) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

How to Use SAL in Existing Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Banned APIs Are Removed from the Codebase . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Banned Cryptography Removed from the Codebase . . . . . . . . . . . . . . . . . . . . . . . . .

Static Analysis Used to Find and Fix Bugs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Warnings Related to /analyze . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10


Application Verifier Warnings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
FXCop Warnings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11

What do you think of this book? We want to hear from you!


Microsoft is interested in hearing your feedback so we can continually improve our books and learning
resources for you. To participate in a brief online survey, please visit:

www.microsoft.com/learning/booksurvey/

vii

viii

Table of Contents

Unmanaged C/C++ Compiled with /GS and Linked with


/SafeSEH, /DynamicBase and /NXCompat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
Call to Action. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
References . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12

User Account Control, Tokens, and Integrity Levels . . . . . . . . . . . . . . . . 13


User Account Control in Depth . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
Starting at the BeginningUser Tokens . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
Elevating to Administrator. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
A Slight Variant: Administrator with Approval Mode . . . . . . . . . . . . . . . . . . . . 18
The Updated Windows Vista Token Format . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
Determining if a Process Is Elevated . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
How to Require an Application Run as an Administrator. . . . . . . . . . . . . . . . . . 22
Make an Application Prompt for Credentials or Consent . . . . . . . . . . . . . . . . . 24
Starting COM Components with the COM Elevation Moniker . . . . . . . . . . . . . 25
Starting Elevated Managed Code Applications . . . . . . . . . . . . . . . . . . . . . . . . . . 27
User Interface Considerations. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
Virtualization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
How to Disable Virtualization for Your Application . . . . . . . . . . . . . . . . . . . . . . 31
Integrity Levels . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
Rules for Integrity Settings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
The NW, NR, and NX Masks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
A Defensive Model Using Integrity Levels . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
Debugging Application Compatibility Issues in Windows Vista . . . . . . . . . . . . . . . . . 42
File Warnings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
Registry Warnings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
INI Warnings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
Token Warnings. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
Privilege Warnings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
Name Space Warnings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
Other Objects Warnings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
Process Warnings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
The Importance of Code Signing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
Privileges New to Windows Vista. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
SE_TRUSTED_CREDMAN_ACCESS_NAME
(SeTrustedCredManAccessPrivilege) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44
SE_TRUSTED_CREDMAN_ACCESS_PRIVILEGE (31L). . . . . . . . . . . . . . . . . . . . . . . 44
SE_RELABEL_NAME (SeRelabelPrivilege) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45

Table of Contents

ix

SE_RELABEL_PRIVILEGE (32L) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
SE_INC_WORKING_SET_NAME (SeIncreaseWorkingSetPrivilege) . . . . . . . . . . 45
SE_INC_WORKING_SET_ PRIVILEGE (33L) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
SE_TIME_ZONE_NAME (SeTimeZonePrivilege) . . . . . . . . . . . . . . . . . . . . . . . . . 45
SE_TIME_ZONE_ PRIVILEGE (34L) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
SE_CREATE_SYMBOLIC_LINK_NAME (SeCreateSymbolicLinkPrivilege) . . . . . 45
SE_CREATE_SYMBOLIC_LINK_ PRIVILEGE (35L). . . . . . . . . . . . . . . . . . . . . . . . . . . 45
Call to Action . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
References . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46

Buffer Overrun Defenses . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49


ASLR. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
Limitations of ASLR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
Performance and Compatibility Implications . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
Stack Randomization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
Performance and Compatibility Implications . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
Heap Defenses . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
NX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
Performance and Compatibility Implications . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
/GS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
SafeSEH . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
Summary. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
Call to Action . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
References . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72

Networking Defenses . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
IPv6 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76
Teredo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
Network List Manager . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
The Windows Vista RSS Platform . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82
Winsock Secure Socket Extensions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
Windows Firewall with Advanced Security . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85
Global Firewall Settings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85
Creating Rules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
Working with Rule Groups . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
Call to Action . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95
References . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95

Table of Contents

Creating Secure and Resilient Services . . . . . . . . . . . . . . . . . . . . . . . . . . . 97


Services Overview. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97
Service Accounts. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99
Reducing Privileges . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102
Controlling Network Access . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107
Communicating with the Desktop . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110
Simple Message Boxes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112
Shared Memory. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112
Named Pipes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112
Sockets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116
RPC/COM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117
Lessons from the School of Hard Knocks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117
Call to Action. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118
References . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119

Internet Explorer 7 Defenses. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121


Pervasive Defenses . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122
ActiveX Opt-In . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122
Protected Mode . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124
Data Execution Prevention (DEP) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126
cURL and the IUri Interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 130
Lock Your ActiveX Control. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131
Other Things You Should Know About Internet Explorer 7 . . . . . . . . . . . . . . . . . . . . 132
Clipboard Access Is Disabled. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132
Script URLs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132
Good-bye PCT and SSL2 (and Good Riddance), Hello AES!. . . . . . . . . . . . . . . 132
Window Origin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133
Call to Action. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133
References . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134

Cryptographic Enhancements. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135


Kernel Mode and User Mode Support . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136
Crypto-agility . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136
Crypto-Agility in CNG . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137
New Algorithms in CNG . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 139
Using CNG . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 140

Table of Contents

xi

Encrypting Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141


Hashing Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141
MACing Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141
Generating Random Numbers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142
CNG and FIPS. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142
Improved Auditing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143
Something Missing from CNG . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144
SSL/TLS Improvements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144
SSL/TLS Revocation Checking and OCSP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145
Root Certificates in Windows Vista. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148
Deprecated Crypto Features in Windows Vista . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148
Call to Action . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148
References . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 149

Authentication and Authorization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 151


Windows CardSpace and Information Cards . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 151
The Information Card Data Flow. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 152
Windows CardSpace and Phishing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153
CardSpace and Phishing An Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 154
Seeing Information Cards in Action . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156
Whats in an Information Card?. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156
Programmatically Accessing Information Cards . . . . . . . . . . . . . . . . . . . . . . . . . 157
CardSpace Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 159
Graphical Identification and Authorization (GINA) Changes . . . . . . . . . . . . . . . . . . . 159
Owner SID Changes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 160
Call to Action . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 161
References . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 161

Miscellaneous Defenses and Security-Related Technologies . . . . . . . . 163


Adding Parental Controls Support to Your Application . . . . . . . . . . . . . . . . . . . . . . . 164
The Code. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 165
Time Limits . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 165
The 450 Error . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 166
Detecting Whether Block file downloads Is Enabled . . . . . . . . . . . . . . . . . . . 166
Turning Off Filtering for Your Application or URL . . . . . . . . . . . . . . . . . . . . . . . 166
Logging Events. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167
Windows Defender APIs. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167
Read the Windows Defender Policy Documentation! . . . . . . . . . . . . . . . . . . . . 168

xii

Table of Contents

Sign Your Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 169


Request to Be Added to the Windows Defender Known or
Not Yet Classified Lists . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 169
New Credential User Interface API. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 169
Use the Security Event Log . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 171
Pointer Encoding . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 172
Kernel Mode Debugging Issues . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 175
Programming the Trusted Platform Module (TPM) . . . . . . . . . . . . . . . . . . . . . . . . . . 175
Low-Level Access to the TPM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 177
Windows SideBar and Gadget Security Considerations . . . . . . . . . . . . . . . . . . . . . . . 181
References . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 182
Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 183

What do you think of this book? We want to hear from you!


Microsoft is interested in hearing your feedback so we can continually improve our books and learning
resources for you. To participate in a brief online survey, please visit:

www.microsoft.com/learning/booksurvey/

Foreword
Writing Secure Code for Windows Vista is a very important book for everyone in the hightechnology industry. The ideas expressed in this book represent the latest thinking in creating
the trustworthy experience every user of technology expects.
Microsofts vision for the use of technology by all segments of society is based on the notion that
Moores law will continue, creating ever more powerful, and ever less expensive, computers that
can be applied in an increasing number of ways to meet the needs of all types of people. With
the continued growth in broadband networks, including new wireless technologies, these
devices will be connected to each other locally and across the world, giving people unprecedented access to information, media, and services with a level of convenience we are only starting to fathom. This vision is not only Microsofts; it is shared by many across the hightechnology industry. No matter your commercial or technological allegiance, this vision spells
out how our industry will grow, how we will generate commercial success for our businesses,
and how we will all contribute to a world that is more convenient for everyone and that allows
every person to reach his or her full potential. It is a wonderful visionand none of us can wait
to get there.
There is one important baseline requirement to fulfill this vision. If people of all walks of life
are to join us in this wonderful, connected, digital world, they will need to trust the technology. People want to know that their privacy is guaranteed. People want to know that their critical information is safe from theft and vandalism. People want their experience to be reliable
and simple. This is growing harder all the time.
At Microsoft, we track the activities of the hackers and criminals who work on Internet very
closely. The environment is growing more complicated: offenders range from people who
hack into systems for fun and fame to organized crime. It is estimated that Internet-based
criminals caused billions of dollarsin losses across the world. That kind of money can fund a
lot of engineering, and it means criminals are more persistent than ever in finding even the
most obscure vulnerability in every kind of high-technology product. It is no longer feasible to
assume that nobody will notice a vulnerability in a product. We have reached the age where if
a vulnerability is present, it will get noticed and exploited.
As hacking for profit grows, the criminal community is becoming more organized in sharing
information on vulnerabilities. We now live in an environment where criminals specialize in
weaponizing vulnerability information, driving the time between the identification of a vulnerability and a profitable exploit of that vulnerability to zero. These specialized criminals are
the arms dealers of organized crime on the Internet, and they sell their wares to the highest
bidder.
Because of the evolution of the criminal hacker community, it is even more important for
everyone producing high-technology products to use rigorous engineering standards, such as
xiii

xiv

Foreword

the Secure Development Lifecycle, to minimize the chance that there is a vulnerability in a
product. Because high-technology products are made by human beings, there is no guarantee
of zero vulnerabilities. However, we as an industry can band together and use our community
to maximize our defenses.
As a software platform, Windows has a special role in helping software companies of all kinds
make it as easy as possible to deliver software that is secure from vulnerabilities and exploits.
Writing Secure Code for Windows Vista was written to aid anyone writing a Windows application to follow security best practices that are proven to deliver fundamentally more secure software products. Windows Vista was designed with features that give software writers platform
tools that aid in making their software secure. These features represent Microsofts best understanding of what software applications need in the areas of authentication, data protection,
and protection from exploits. By using the new security features of Windows Vista, applications become more secure and trustworthy in customers eyes.
The journey to create the connected digital vision is a long one, and there will be many fits
and starts as the high-technology industry works together to deliver convenience and value to
all types of people. One important requirement of success is creating technology products
that people trust. Writing Secure Code for Windows Vista will help all of us deliver fundamentally more secure and trustworthy products to our customers.
Jon DeVaan
Senior Vice President of Engineering Excellence
Microsoft Corporation
February 2007

Acknowledgments
We have now written four books together so far, and we are proud of every one. Writing books
is never easy, but its made a lot easier when you have a great group of people helping you
along the way. What sets this book apart from the other is the list of acknowledgements. Its
huge! In fact, the list is so big we have decided to break it up into groups! Every person listed
below contributed something to this book, from code review to fact checking and from little
ideas to making sure we covered critically important topics.

Secure Windows Initiative and SDL teams


David Ross, Nitin Kumar Goel, John Lambert, Steve Lipner, Andrew Roths, Neill Clift, Richard
Johnson, Matt Thomlinson, Josh Lackey, Damian Hasse, and Robert Hensing.

Windows Core Security


Darren Canavor, Ben Nick, Anderson Quach, Yu Chen, Tolga Acar, David Cross, Steve Hiskey,
Tomas Palmer, Peter Brundrett, Oded Ye Shekel, Art Baker, Niels Ferguson, Ari Medvinsky,
Chris Corio, George Li, John Brezak, Kelvin Yiu, Dan Fritch, Jon Schwartz, Mike Lai, Eric
Fitzgerald, Jeff Williams, Nate Lewis, Brian Brown and Satyajit Nath

Windows
Dave Cutler, Saji Abraham, Daniel Wang, Hunter Hudson, Gov Maharaj, Richard Ward, Walter
VonKoch, Sean Lyndersay, Mike Sheldon, Sandeep Singhal, Henry Sanders, Neeraj Garg,
Deepak Bansal, Ravi Rao, Stan Pennington, David Bennett, David Kennedy, Landy Wang,
Chuck Reeves, Andy Harjanto, Kim Cameron, Mike B. Jones, Garrett Serack, Brent Schmaltz,
Adrian Marinescu, Ramesh Chinta, Chittur Subbaraman, Christian Huitema, Eran Yariv, and
Mahesh Mohan.

Internet Explorer
Marc Silbey, Rob Franco, Dean Hachamovitch, Jeremy Dallman, Zhenbin Xu, Eric Lawrence,
Alex Kuang, Tariq Sharif, Joshua Allen, Venkat Kudallur, and Chris Wilson.

Microsoft Office
Alan Myrvold, Tom Gallagher, Lawrence Landauer, Hidetake Jo, and Mike Marcelais.

Developer Division
Mark Lacey

xv

xvi

Acknowledgments

Microsoft Consulting
Aaron Margosis

Microsoft Press
Devon Musgrave, as usual guided us seamlessly through the book-writing process and to Ben
Ryan for agreeing to do the book. Valerie Woolley our editor was a dream to work with. One
thing we both love about working with Microsoft Press, is the editors dont try to force their
style over our writing style. And we appreciate that!
And to anyone we missed. Were sorry.
Michael Howard
David LeBlanc
Redmond, WA
March 2007

Introduction
In this Introduction:
Target Audience . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xviii
How does this Book Relate to Writing Secure Code? . . . . . . . . . . . . . . . . . . . . . . xviii
How to Read This Book. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xix
Getting Started with the Code in this Book. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xx
What's on the Companion Web Site? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xxi
System Requirements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xxi
Microsoft Press Support . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xxii
Computers hooked up to the Internet are attacked and compromised every day. There is no
doubt that attackers are moving further up the software stack and attacking software installed
on computers. This may in part be due to software vendors spending more time shoring up
the defenses of their operating systems. Between the release of Windows XP in 2001 and
Windows Vista in 2006, the security landscape evolved dramatically: while attacks are much
more common, more troublesome is the rise in system compromises. You often hear that Windows is the most attacked platform. Thats true, so the next comment may seem alarming: we,
the authors, are not overly concerned about attacks, attacks will always happen. It is compromises that people ought to be worried about. And this made people at Microsoft think long
and hard about how to make Windows Vista a considerably more secure product.
Windows Vista is the most secure operating system released by Microsoft. The sheer magnitude of defensive engineering added to the operating system is staggering, and we were
actively involved in many of these defenses. Even with all this work, attacks will continue.
Were not saying Windows Vista will have no security bugs, it will; but numerous defenses
have been added to the operating system to reduce the likelihood that attacks successful and
to reduce the chance that a vulnerability can be exploited in the first place. The goal of these
defenses is to reduce the likelihood of compromise.
So what are you doing to secure your application in light of the increased attack potential?
Remember, attacks will happen! Just because your application may not have the word
Microsoft in its title does not mean it wont be attacked! What makes security a fascinating
subject is that unlike, say, computer performance or reliability, which are disciplines that
focus on person vs. computer issues, security is all about person vs. person. Security issues
will never completely go away because there will always be the malevolent human
influence.
In addition to tidying up the code, and fixing design problems, Microsoft has also made a
huge amount of new functionality available that everyone can use to make applications more
xvii

xviii

Writing Secure Code for Windows Vista

secure. Unlike our previous books, which largely covered fundamentals, this book outlines
how your applications that run on top of Windows Vista can take advantage of these defenses
to protect shared customers. This book goes beyond the basic defensive strategies you can
employ to also cover the some of the new security features you can use to add defenses to your
applications to help you meet business you or your customers objectives.
Microsoft has spent over five years adding defenses and new, modern security features to
Windows Vista, and you can use these defenses and security features within your application
to reduce the chance your application is compromised. You can reduce the chance of attack in
three ways:

Reduce affected users if no one uses your application, youre not worth attacking.

Reduce the attack surface components that have fewer points of entry (especially by
default) are attacked less often.

Harden your attack surface to the point that something else becomes the path of least
resistance.

We really dont advise taking the first approach, but this is what will happen if you dont pay
attention to security and stay current. The last two approaches are what wed like to help you
with, to you can- protect your customers by taking advantage of operating system defenses
and features, and that is the simple goal of this book to explain how you can use these
Windows Vista features.

Target Audience
The target audience for this book is primarily developers building software for Windows
Vista. There are some design considerations in the book too, so designers and architects will
get some benefit. Note however, that this book is very code-heavy.
It is also assumed you have some knowledge of the Windows authentication and authorization system. While some background information is provided in this book, it is assumed the
reader knows how objects are protected in Windows. If you do not, you should read a book
such as Windows Internals Fourth Edition, by Mark Russinovich and David Solomon (Microsoft
Press 2005).

How does this Book Relate to Writing


Secure Code?
The first and second editions of Writing Secure Code (Microsoft Press) mainly focused on core
secure coding principles, and touched on design and testing principles too. This book teaches
and demonstrates how best to use the new security defenses and features within Windows
Vista. If you already have Writing Secure Code, then Writing Secure Code for Windows Vista

Introduction

xix

contains design and coding best practice as they apply to Windows Vista. This book is not a
superset of Writing Secure Code, this book is an adjunct to Writing Secure Code.

How to Read This Book


This book is short, and if you are planning or presently writing software to target Windows
Vista, then you really should read the entire book - if for no other reason than to give you a
good feel for the new security defenses and technologies Microsoft has added or improved in
Windows Vista.
Each of the chapters is relatively self-standing, except for the first three which all developers
building software for Windows Vista should read.
Chapter 1, Code Quality describes many of the changes that were made to Windows Vista at
a code level to remove potential security bugs. There is much the software industry can learn
from what Microsoft did to help secure Windows Vista, and there is nothing more wed love
to see but for other developers to learn from what we have learned.
Chapter 2 User Account Control, Tokens, and Integrity Levels and Chapter 3 Buffer Overrun
Defenses should be read because the technologies described in these two chapters affects every
other feature in Windows Vista.
Most if not all developers will write networked applications, so they should digest the contents of Chapter 4, Networking Defenses.
Those developers writing services should read Chapter 5, Creating Secure and Resilient
Services, as we offer guidance to make your services more resilient to attack and making it
easier to create services that run with the lowest possible privilege.
If you create code for Internet Explorer, such as browser helper objects, toolbars or ActiveX
controls, then you should read Chapter 6, Taking Advantage of Internet Explorer Defenses.
Internet Explorer 7 in Windows Vista has a number of architectural changes and defenses
that will affect how your code will run.
If your software uses cryptographic functions, then you should read Chapter 7, Cryptographic Changes in Windows Vista because we have included a newer crypto architecture
named Cryptography API: Next Generation (CNG) as well as adding updated algorithms and
certificate revocation and validation.
Enterprise developers will get the most benefit from Chapter 8, Authentication and Authorization which outlines the authentication and, ACL in Windows Vista.
The final chapter, Miscellaneous Defenses is admittedly a catch-all of new defenses added
to Windows Vista that do not fit in any other chapter. You should spend some time perusing
this chapter to determine if any of the features and defenses apply to the software you are
creating.

xx

Writing Secure Code for Windows Vista

Getting Started with the Code in this Book


All the code in this book was written primarily in C, C++ and, to a lesser extent, C#
using Microsoft Visual Studio 2005 Team Suite Service Pack 1 and the Windows Software
Development Kit (SDK). For C and C++ development Visual Studio was installed first
followed by the Windows SDK. Next, we added references to the various Windows SDK
headers and libraries to Visual Studio so it would read from the updated directories first. You
can do this by performing the following steps:
1. Open Visual Studio
2. Select Tools | Options
3. Navigate to and expand Projects and Solutions
4. Select VC++ Directories
5. Click the New Line icon
6. Add the directory to the Windows SDK include files
Repeat the steps above for the executable and library files. The following figure shows the dialog in question. You can also simply accept the option to update your environment when you
install the SDK remember to restart the development environment.

Finally, you should add the following line before you include any header files in your application. A good place is the first line in stdafx.h.
#define _WIN32_WINNT 0x0600

If you dont add this line to your code, your code will probably fail to compile if it references
functions, definitions, constants or structures new to Windows Vista.

Introduction

xxi

Important

Note that all the sample C and C++ code makes full use of SAL (described in
chapter 1) where appropriate and compiles with no warnings at warning level 4 (/W4) and
has no PREfast warnings (/analyze.) The only exception is where we show examples of insecure practices.

For C# development there is no need to change anything to the development environment so


long as you are running on a Windows Vista computer.

Whats on the Companion Web Site?


All the code samples discussed in this book can be downloaded from the books companion
content page at the following address:
http://www.microsoft.com/mspress/companion/0978735623934
Make sure you read the readme file as it describes all the sample code.

System Requirements
Any Windows Vista capable machine can run the sample code that accompanies this book
and is locate on the companion Web site. The Minimum Requirements for Windows
Vista are:

800 megahertz (MHz) processor

512 megabytes (MB) RAM

DirectX 9-capable graphic processor

20 gigabytes (GB) hard disk drive capacity with 15GB available space

To get a better Windows Vista experience, including Windows Aero visual effects, your
computer needs to meet these minimum requirements:

1GHz processor

1 GB of system memory

DirecteX 9-capable graphics processor with a Windows Vista Display Driver Model
(WDDM) driver, 128 GB of graphics memory (if the GPU uses dedicated memory otherwise, no additional graphics memory is required), Pixel Shader 2.0 and 32 bits per pixel.

40 GB hard disk drive capacity with 15 GB available space

Internal or external DVD-ROM drive

Audio output capability

Internet access capability

xxii

Writing Secure Code for Windows Vista

Microsoft Press Support


Every effort has been made to ensure the accuracy of this book. As corrections or changes are
collected, they will be added to a Microsoft Knowledge Base article.
Microsoft Press provides support for books and companion content at the following Web site:
http://www.microsoft.com/learning/support/books/.

Questions and Comments


If you have comments, questions, or ideas regarding the book or companion Web site, or
questions that are not answered by visiting the sites above, please send them to Microsoft
Press via e-mail to:
[email protected]
Or via postal mail to:
Microsoft Press
Attn: Writing Secure Code for Windows Vista Editor
One Microsoft Way
Redmond, WA 98052
Please note that Microsoft software support is not offered through the above addresses.

Chapter 1

Code Quality
In this chapter:
The Windows Vista Quality Gates . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
All C/C++ String Buffers Annotated with SAL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
Banned APIs Are Removed from the Codebase . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
Banned Cryptography Removed from the Codebase . . . . . . . . . . . . . . . . . . . . . . . . . 9
Static Analysis Used to Find and Fix Bugs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
Unmanaged C/C++ Compiled with /GS and Linked with /SafeSEH,
/DynamicBase/, and NXCompat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .11
Call to Action . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .11
References. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .12
Code qualityand security is a subset of qualityis critically important in the field of software.
In fact, nothing is more important than code quality, with the possible exception of good
design. In Windows Vista we spent a great deal of time reducing the chance that developers
will inject new security bugs into the operating system, as well as finding bugs and removing
them from the codebase.
With that said, getting the code and design 100 percent secure is impossible because security
is a constant arms race between software developers and attackers. All you can strive for is to
raise the security bar as far as possible in your code and to continue to do so as you create new
code. And this is why other defenses are so important: there will always be design and code
security bugs, but defenses can often eliminate a bug or reduce the chance that an attack will
be successful. This chapter focuses on getting the code right; it does not discuss designlevel issues that can be found through threat modeling. A good reference for the present
threat modeling state of the art can be found in The Security Development Lifecycle (Howard
and Lipner 2006).
The security engineering effort in Windows Vista is simply astronomical, and you can implement many of the process changes we made to Windows Vista within your own organization.
This chapter outlines what we did (a) to help reduce the chance that developers will add new
security bugs to the code and (b) to find existing bugs.
Note

This chapter does not focus on defensive features available in Windows Vista; rather,
it outlines some of the process improvements and code changes we made to the operating
system.
1

Writing Secure Code for Windows Vista

Two of the major tasks undertaken in Windows Vista were removing banned application programming interfaces (APIs) and adding Standard Annotation Language (SAL) annotations to
C functions and C++ methods. Both these tasks, explained later in this chapter, proved very
effective at finding and removing security bugs. An analysis of 63 buffer-related security bugs
that did not affect Windows Vistabut that did affect Windows 2000, Windows XP, or
Windows Server 2003discovered the following:

Code annotated with SAL caught 27 (43 percent) of the bugs.

Code that used banned APIs accounted for 26 (41 percent) of the bugs.
Not Found
16%

Found through
SAL 43%

Banned API
Removal
41%
Figure 1-1

Chart of bugs prevented in Windows Vista because of banned API removal and SAL
annotation.

In other words, the combination of SAL and banned API removal alone meant 84 percent of
the buffer-related security bugs found in versions of Windows prior to Windows Vista did not
affect Windows Vista because the bug was found via SAL or the problem was solved because
the banned API was removed and replaced with a safer function. Of course, classes of bugs
exist that will not be prevented through the use of SAL and banned API removal.
Stop and think about these figures for moment. Removing banned APIs is pretty straightforward and adding SAL annotations is not particularly complex, yet doing these two tasks
found or prevented 52 out of 63 bugs! I think by any measure this is a great example of bang
for the buck! One bug was prevented because of banned API removal and SAL annotation,
which indicates that to be effective, you must perform both tasks on your code.
This chapter starts with a brief explanation of the Windows Vista Quality Gates and then continues by describing the security requirements required by the quality gates.

The Windows Vista Quality Gates


Windows Vista introduced a number of quality gates that encompassed security, privacy,
reliability, performance, and others. The goal of the quality gates was to throttle code that
entered the operating system to make sure it complied with the practices defined by that

Chapter 1

Code Quality

quality gate. For example, the security quality gate had the following requirements, which we
will discuss throughout this chapter:

All C/C++ string buffers annotated with SAL

Banned APIs removed from the codebase

Banned cryptography removed from the codebase

Static analysis used to find and fix bugs

Unmanaged C/C++ compiled with /GS and linked with /SafeSEH, /DynamicBase and
/NXCompat

Essentially, new code must pass the quality gate before it can be accepted into the Windows
Vista source code tree. The quality gates apply to all developers, and are a very simple and
effective way of reducing bugs that enter the system. But most importantly, the quality gates
are a means to enforce code policy. Many, but not all, of the security quality gate requirements
are derived from the Security Development Lifecycle (SDL). In fact, some security quality gate
requirements, as they apply to Windows Vista, go above and beyond the SDL requirements.
The rest of this chapter focuses on the Windows Vista security quality requirements in detail.

All C/C++ String Buffers Annotated with SAL


The goal of the Standard Annotation Language (SAL) is to enable programmers to explicitly
state the contracts between implementations (callees) and clients (callers) that are implicit in
the C and C++ source code. The main benefit of SAL is that you can find more code bugs with
some upfront work. We have found that the process of adding SAL annotations to existing
code can also find bugs as the developer questions the assumptions previously made about
how the function being annotated works. By this we mean that as a developer adds annotations to a function, she must think about how the function works in more detail than simply
assuming it was written correctly. This process finds assumption flaws.
Important

You should know that SAL comes in two flavors: one is called declspec syntax,
and the other is attribute syntax. Windows Vista uses the former, and the examples in this
book also follow the declspec syntax. However, Microsoft Visual Studio 2005 does support
both syntaxes.

When you annotate a function with SAL, any code that calls that function will get the benefit
of the annotation. To this end, we have annotated the majority of C runtime functions
included with Visual Studio 2005 and the Windows functions included in the Windows Vista
Software Development Kit. This means youll get the benefit of the annotations added by
Microsoft, and you might find bugs lurking in your code.
SAL defines proper use of buffers. A C/C++ pointer can be used to represent the address of a
single object, or an array of objects. Sometimes the size is known at compile time, and

Writing Secure Code for Windows Vista

sometimes its only known at run time. Because C/C++ pointer types are overloaded, you
cant rely on the type system to help you program with buffers properly! Thats why we have
SAL.
The Windows Vista security quality gate stated that all mutable non-constant string buffers
for new features must be annotated with SAL. In reality, this translated into all functions that
read from or write to a buffer.

SAL by Example
Probably the best way to explain SAL is by showing an example. Lets say you have a C/C++
function:
void FillString(
TCHAR* buf,
size_t cchBuf,
TCHAR ch) {
for (size_t i = 0; i < cchBuf; i++)
buf[i] = ch;
}

We wont insult your intelligence by explaining what the function does, but what makes this
code interesting is that two of the arguments, buf and cchBuf, are closely linked: buf
should be at least cchBuf characters long. If buf is not as big as cchBuf claims it is, then the
FillString function could overflow the buf buffer. If you compile the code below with Visual
Studio 2005, at warning level 4 (/W4) youll see no warnings and no errors, yet clearly a
buffer overrun vulnerability is in this code:
TCHAR *b = (TCHAR*)malloc(200*sizeof(TCHAR));
FillString(b,210,'x');

What SAL does is allow a C or C++ developer to inform the compiler of the relationship
between the two arguments by using syntax such as this:
void FillString(
__out_ecount(cchBuf) TCHAR* buf,
size_t cchBuf,
TCHAR ch) {
for (size_t i = 0; i < cchBuf; i++)
buf[i] = ch;
}

Note the use of __out_ecount(n) just before buf in the argument list. This is a macro that wraps
some very low-level SAL constructs you should never have to worry about, but in essence
__out_ecount(n) means this:
buf is an out parameter, which means it will be written to by the callee, and buf cannot be
NULL. The length of buf is n elements, in this case cchBuf TCHARS.

Chapter 1

Code Quality

When this code is compiled with a Microsoft C++ compiler that has the /analyze option, such
as the version shipped with Visual Studio 2005 Team Suite or any of the Visual Studio Team
System products, or cl.exe included with the Windows Vista Software Development Kit, youll
see output like this:
c:\code\saltest\saltest.cpp(54) : warning C6203: Buffer overrun for non-stack buffer 'b'
in
call to 'FillString': length '420' exceeds buffer size '400'
c:\code\saltest\saltest.cpp(54) : warning C6386: Buffer overrun: accessing 'argument 1',
the writable size is '200*2' bytes, but '420' bytes might be written: Lines: 53, 54
c:\code\saltest\saltest.cpp(54) : warning C6387: 'argument 1' might be '0': this does not
adhere to the specification for the function 'FillString': Lines: 53, 54

There are many other SAL macros, including:

__in
The function using __in will only read from the single-element buffer, and the buffer must be
initialized (not NULL); as such __in is exactly the same as __in_ecount(1) and __in is implied
if the argument is a const. In fact, __in is somewhat redundant, and its better to use const
because the compiler can perform better optimizations in some cases.
The following function prototype shows how you can use __in:
BOOL AddElement(__in ELEMENT *pElement);

__out
The function using __out fills a valid (not NULL) buffer, and the buffer can be dereferenced by
the calling code. The following function prototype shows how you can use __out.
BOOL GetFileVersion(
LPCWSTR lpsFile,
__out FILE_VERSION *pVersion);

__in_opt
The function using __in_opt expects an optional buffer, meaning the buffer can be NULL. The
following code shows how you could use __in_opt. In this example, if szMachineName is
NULL, the code will return operating system information about the local computer.
BOOL GetOsType(
__in_opt char *szMachineName,
__out MACHINE_INFO *pMachineInfo);

Writing Secure Code for Windows Vista

__inout
The function using __inout expects a readable and writeable buffer, and the buffer must be
initialized by the caller. Here is some sample code that shows how you might use __inout.
size_t EncodeStream(
__in HANDLE hStream,
__inout STREAM *pStream);

__inout_bcount_full(n)
The function expects a buffer that is n-bytes long that is fully initialized on entry and exit.
Note the use of bcount rather than ecount: b means bytes and e means elements; for example, a Unicode string in Windows that is 12 characters (an element in SAL parlance) long is 24
bytes long. There is an element variant too: __inout_ecount_full(n). The following code example takes a BYTE * that points to a buffer to switch from big-endian format to little-endian format so it makes sense that the incoming buffer is fully initialized and is a fully initialized buffer
on function exit. Youll also see another SAL macro in the function prototype, __out_opt,
which means the data will be written to by the function, but it can be NULL. In the case of a
NULL exception point, the function will not return exception data to the caller.
void ConvertToLittleEndian(
__inout_bcount_full(cbInteger) BYTE *pbInteger,
DWORD cbInteger,
__out_opt EXCEPTION *pException);

__inout_bcount_part(n,m)
The__inout_bcount_part(n,m) annotation is a variant of __inout_bcount_full, but rather than
initializing the entire buffer, the code will only fill up to m-bytes in the destination buffer. The
following function prototype implies that Read() will copy no more than cbCount bytes into
pBuff, and the actual number of bytes is reflected in pcbHowMuchRead. Note that the function
will return one size_t argument as the last argument, unless its NULL (the opt part of the
SAL macro name).
HRESULT Read(
__inout_bcount_part(cbCount, *pcbHowMuchRead) LPVOID pBuff,
__in size_t cbCount,
__out_ecount_opt(1) size_t *pcbHowMuchRead);

There is an element variant too: __inout_ecount_part(n).

__deref_out_bcount(n)
The function argument marked with __deref_out_bcount(n) when dereferenced will be set to
an uninitialized buffer of n-bytes, in other words, *p is initialized, but **p is not.

Chapter 1

Code Quality

HRESULT StringCbAlloc(
size_t cb,
__deref_out_bcount(cb) char **ppsz) {
*ppsz = (char*)LocalAlloc(LPTR, cb);
return *ppsz ? S_OK : E_OUTOFMEMORY;
}

There is an element variant, too, __deref_out_ecount(n).


SALs usefulness extends beyond function arguments. It can also be used to detect errors on
function return. If you look closely at the list of warnings earlier in this document, youll
notice a third one:
c:\code\saltest\saltest.cpp(54) : warning C6387: 'argument 1' might be '0': this does not
adhere to the specification for the function 'FillString': Lines: 53, 54

This bug really has little to do with any function argument, rather it occurs because the code
calls malloc() but does not check that the return value from malloc() is non-NULL. If you look
at the function prototype for malloc() in malloc.h in Visual Studio 2005 or the Windows Vista
Software Development Kit, youll see this:
__checkReturn __bcount_opt(_Size) void *__cdecl malloc(__in size_t _Size);

Because the return from malloc() could be NULL (because the function may fail), we use a
__bcount_opt(n) SAL macro (note the use of opt in the macro name). If we change the code
that calls malloc() to check the return is non-NULL prior to calling FillString, the C6387 warning goes away. Dont confuse an optional NULL return value with __checkReturn; the latter
detects whether you ignored the result altogether. For example:
size_t cb = 10 * 12;
malloc(cb);

This code will yield this warning when compiled with /analyze:
c:\code\saltest\saltest.cpp(30) : warning C6031: Return value ignored: 'malloc'

How to Use SAL in Existing Code


This section describes the recommended work flow for adding SAL annotations to existing
code.

Make sure you have a solid code baseline that compiles cleanly.

Determine ahead of time which SAL annotations you are going to use. For example, are
you going to focus on annotating read and write buffers, or write buffers exclusively?

Make sure to #include sal.h in your code.

Annotate the necessary function prototypes in your headers.

Writing Secure Code for Windows Vista

A great SAL documentation source is the comment block at the start of the sal.h header file, as
well as the SAL annotations already in the Windows Vista Software Development Kit headers
and the C runtime headers included with Visual Studio 2005.
In addition to using SAL, proper use of Hungarian notation (Simonyi 1999) around string
buffers can help prevent problems. If you know that cbCount is a count of bytes, and cchCount
is a count of characters, this can be helpful in spotting problems during code review. While its
possible to go overboard with Hungarian notation, using it with buffer size variables will save
you a lot of trouble.

Banned APIs Are Removed from the Codebase


The SDL requires that new C and C++ code should not use banned C runtime (CRT) or
banned Windows base functions. Most of these banned functions deal with buffers at run time
and are a common source of many buffer overruns. At Microsoft we simply ban a function if it
is shown to lead to consistently insecure software. The Windows Vista team went one step
beyond SDL by actively removing most instances of banned functions. We say most because in
some cases there is no need to replace a function with a safer function if the source buffer is
trusted. For example, the code below is utterly safe because the source string is a constant;
there is no way the attacker can change this string short of patching the binary directly.
const char *src = "Hello, World!";
char dst[32];
strcpy(dst,src);

A security purist would say this code should be changed to use a safer function call, but the
realist would make no change because the code is safe. By the way, the purist would win the
argument if the source buffer increases because of localization!
Tip

If you decide not to replace a banned API with a safer alternative, you should add a
comment to the code explaining why the API is not replaced. This will save time in the future
when someone asks, Why didnt we replace this function?

The list of banned APIs is not static; it evolves if bugs are found. That being said, the list of
banned APIs at Microsoft has not changed in several years. When analyzing security bugs, we
make a note of the offending function calls, if any, and if we see the function call used in three
or more security bugs, we ban that function for new code. But we can only ban the function if
there is a viable replacement.
The good news is the process of removing banned APIs is pretty much a no-brainer if you use
Visual Studio 2005 because all banned APIs are deprecated. If your code uses a banned API,
the compiler will emit a C4996 warning:
c:\code\test.cpp(101) : warning C4996: 'wcscpy': This function or variable may be unsafe.
Consider using wcscpy_s instead.

The list of banned APIs as it stands is listed at http://msdn.microsoft.com/security.

Chapter 1

Code Quality

Banned Cryptography Removed from


the Codebase
Removing banned cryptographic algorithms from the code is much harder than simply
replacing banned APIs because its harder to confine the change. When you replace a banned
API, the change is usually a one-line change. Changing a cryptographic algorithm possibly
requires new key sizes, different buffer sizes for holding hash function results, and so on.
Then theres the problem of interoperability and compatibility with standards, different
operating systems or a competing product, or perhaps just an older version of your product.
And it all needs thorough testing! In Windows Vista we removed many instances of the
security-related MD4 and MD5 hash algorithms because they are woefully insecure by todays
standards. We could not remove all instances of MD4 and MD5 because of backward compatibility; for example, the digest authentication system requires MD5. This distinct lack of
crypto-agility, or the ability to change a cryptographic algorithm quickly, is worrying. Well
explain cryptographic agility in more detail in Chapter 7, Cryptographic Enhancements and
the list of banned cryptographic algorithms is listed at http://msdn.microsoft.com/security.
Important

You only need to replace security-related calls to banned cryptographic algorithms. For example, if you use MD5 as a glorified checksum, then replacing it with SHA512
is probably overkill. Of course, MD5 is insecure when used to sign a document.

All instances of banned cryptographic algorithms should be triaged to determine if it is


appropriate to change the algorithm to something more secure. Unfortunately, backward
compatibility plays a large influence in leaving the algorithms in the code. With that said, it is
important that you come up with a plan to support crypto-agility.

Static Analysis Used to Find and Fix Bugs


Before your project begins, or if youre already partway through development, you should
identify which static analysis tools you will use to find bugs missed through code review.
During the development of Windows Vista, we used numerous source code analysis tools,
including PREfast, which is included in Visual Studio 2005 Team Suite or any of the Visual
Studio Team System products. You can invoke the PREfast engine through the /analyze
compiler switch.
Application Verifier was used to verify native applications at run time, and we used FXCop
for managed code to verify compliance with SDL requirements.
At a minimum, for native code written in C or C++, you should triage all buffer overrun
and integer overflowrelated warnings regardless of which compiler and static analysis
tools you use. Additionally, there are compiler warnings that arent enabled until you compile
at warning level 4. Some of the additional warnings have significant security implications
and arent replicated in PREfast because it doesnt make sense to provide redundant

10

Writing Secure Code for Windows Vista

warnings. An examination of a large codebase where many of the integer-related warnings had
been disabled found potentially exploitable conditions in about 20 percent of the places
where the warning had been masked.

Warnings Related to /analyze


The /analyze warnings in Table 1-1 should be flagged for triage to determine if they are real
security bugs or not. And please err on the side of caution! A full list of static analysis warnings is available in Code Analysis for C/C++ Warnings on MSDN (MSDN 2005).
Table 1-1

Minimum List of Visual C++ Compiler and /analyze Warnings


You Should Review

Warning Description
4018

Expression: signed/unsigned mismatch

4389

Operator: signed/unsigned mismatch

4244

Conversion: conversion from type1 to type2; possible loss of data

4996

Function: was declared deprecated

6029

Possible buffer overrun in call to <function>: use of unchecked value

6053

Call to <function>: may not zero-terminate string <variable>

6057

Buffer overrun due to number of characters/number of bytes mismatch in call to


<function>

6059

Incorrect length parameter in call to <function>: pass the number of remaining


characters, not the buffer size of <variable>

6200

Index <name> is out of valid index range <min> to <max> for non-stack buffer
<variable>

6201

Buffer overrun for <variable>, which is possibly stack allocated: index <name> is out of
valid index range <min> to <max>

6202

Buffer overrun for <variable>, which is possibly stack allocated, in call to <function>:
length <size> exceeds buffer size <max>

6203

Buffer overrun for buffer <variable> in call to <function>: length <size> exceeds buffer
size

6204

Possible buffer overrun in call to <function>: use of unchecked parameter <variable>

6209

Using sizeof<variable1> as parameter <number> in call to <function> where


<variable2> may be an array of wide characters; did you intend to use character count
rather than byte count?

6248

Setting a SECURITY_DESCRIPTORs DACL to NULL will result in an unprotected object

6383

Setting a SECURITY_DESCRIPTORs DACL to NULL will result in an unprotected object

Also, make sure you review code, looking for constructs that disable any of these warnings.
For example, the following code will disable all 6204 warnings:
#pragma warning ( disable : 6204 )

Chapter 1

Code Quality

11

A more correct way to suppress warnings is to use the following, which only suppresses the
warning on the line of code following the #pragma.
#pragma warning ( suppress : 6204 )

Application Verifier Warnings


Run your native application (written in an unmanaged language such as C or C++) under
AppVerif set to use Basic Tests, and triage all the warnings you see. There are two versions of
AppVerif: one is included with Visual Studio 2005, and the other is a free download. It is recommended that you use the free download because it performs many more checks than the
version in Visual Studio.

FxCop Warnings
Load your managed assemblies into FxCop and then triage all the security rule messages.

Unmanaged C/C++ Compiled with /GS and Linked with


/SafeSEH, /DynamicBase, and /NXCompat
The defenses behind these compiler and linker options are described in detail in Chapter 3,
Buffer Overrun Defenses. In summary, /GS is a compiler switch that adds stack-based buffer
overrun detection to the code. /SafeSEH is a linker option that protects exception handlers,
/DynamicBase randomizes the images base address and /NXCompat is also a linker flag that
means the application will be protected by the CPUs Data Execution Prevention (DEP) capability. DEP is also referred to as No Execute (NX) on AMD CPUs and Execution Disable (XD)
on Intel chips. These options are explained in more detail in Chapter 4.

Call to Action

Consider using SAL for any new code, and annotate functions that take writeable buffers
as arguments. Consider annotating readable buffers too.

Over time you should remove all banned APIs from your C and C++ codebase. Use the
list provided at http://msdn.microsoft.com/security as a starting list. Functions like strcpy
and strcat should be removed first because they are most prone to error.

Over time you should remove all banned cryptography from your codebase. Use the list
of banned cryptographic algorithms provided at http://msdn.microsoft.com/security.
Also start planning for crypto-agility.

Determine as soon as possible a good toolset to use, and draw up a list of warnings you
consider heinous. Any error or warning that relates to buffer overruns or integer overflow problems should be top of the list to fix.

Compile your code with /GS, and link with /SafeSEH, /DynamicBase and /NXCompat.

12

Writing Secure Code for Windows Vista

References
Howard, Michael, and Steve Lipner. The Security Development
Lifecycle. Redmond, WA: Microsoft Press, 2006.

(Howard and Lipner 2006)

Code Analysis for C/C++ Warnings, http://msdn2.microsoft.com/en-us/


library/a5b9aa09(VS.80).aspx. MSDN, 2005.

(MSDN 2005)

Simonyi, Charles, Microsoft Corporation. Hungarian Notation, http://


msdn2.microsoft.com/en-us/library/aa260976(VS.60).aspx. MSDN, reprinted November
1999.

(Simonyi 1999)

Chapter 2

User Account Control, Tokens,


and Integrity Levels
In this chapter:
User Account Control in Depth . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .14
User Interface Considerations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .27
Virtualization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .28
Integrity Levels . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .32
Debugging Application Compatibility Issues in Windows Vista . . . . . . . . . . . . . . .42
The Importance of Code Signing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .44
Privileges New to Windows Vista . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .44
Call to Action . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .45
References. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .46
Windows Vista offers a new set of technologies and defenses that focus on user accounts and
on protecting users from malicious software. One of the earliest design decisions made in
Windows Vista was to make it easier for administrators to control their users desktops by setting them up as ordinary users rather than administrators. When a user runs as an administrator, that user can perform virtually any function, good or bad, on the computer. Security
issues aside for a moment, running as an administrator reduces the reliability of the system
dramatically, and increases support costs because users-as-admins can install any software
they want, load and unload drivers, and so on.
Versions of Windows prior to Windows Vista supported standard users, but many common
tasks simply failed unless the user ran as a full-privilege administrator. In fact, many common
applications simply failed if the applications were not run by an administrator because
the developers did not anticipate users running as standard users in the first place.
Mainly because the older Windows versions (such as the now-unsupported Windows 95 and
Windows 98) had no concept of access control and authorization, so all users were administrators. Hence, code written for Windows 95, Windows 98, and Windows Me could scribble
all over the operating system. But on the operating systems based on Windows NT, Windows
2000, Windows XP, and later, there are access control mechanisms in place, and code cant
write to any place it wishesunless the user is an administrator. Probably the most common mistake made by application developers is to write user data to protected portions
of the file system and registry, such as the Windows and Program Files directories and the
HKLM portion of the registry. Only administrators and sometimes Power Users can write to
13

14

Writing Secure Code for Windows Vista

these locations, and software that writes to these locations will operate correctly only if its
run by high-privilege users. By default, user accounts in Windows XP are administrators, and
because it is the default, software developers assumed this default configuration and built
their software accordingly. While the default for Windows 2000 for a newly created user was
a standard user, Windows 2000 was typically used in a business setting. When Windows XP
is joined to a domain, the default domain user has only limited user rights, and new standard
users are added to the Power Users group for application compatibility.
Important

The Power Users group is deprecated in Windows Vista because it is so powerful; the group is still in the operating system, but no account is in the group, and no Access
Control Lists (ACLs) are left that reference Power User.

Windows Vista changes all the rules. Users are unprivileged users (often referred to as standard users); by default, administrators are unprivileged users as well. The reason Microsoft
enabled standard users to fully use Windows was to reduce the potential threat to the system
if the user or administrator ran malicious software. When code, malicious or not, runs with
full administrative privileges, it is not constrained to portions of the operating systemit can
manipulate any part of the operating system. User Account Control (UAC) enables most
applications to run properly without administrative privileges and provides users with a clear
indication when they launch an action that requires full administrator privileges.
The goal of this chapter is to explain how you can write applications that work correctly and
take advantage of the new user account-related features in Windows Vista. In this chapter we
discuss the following topics:

User account control in depth

User interface considerations

Virtualization

Integrity levels

Debugging application compatibility issues in Windows Vista

Privileges new to Windows Vista

This chapter is code-dense, and the reader is urged to refer to the complete code samples
included in the Ch02 folder of the sample code. Lets get started.

User Account Control in Depth


No security-related feature in Windows Vista has garnered so much public and critical comment as User Account Control (UAC). UAC started life as the Limited User Account (LUA),
then was renamed to User Account Protection (UAP), and finally we got UAC. The move from
UAP to UAC was interesting; the P in UAP implies that UAP offers 100 percent bulletproof
protection, which is simply untrue. UAC certainly offers a useful and viable defense and

Chapter 2

User Account Control, Tokens, and Integrity Levels

15

allows administrators to wield greater control and management over corporate desktops.
However, local escalation of privilege vulnerabilities trump UAC, and every operating system
on the planet has had, and continues to have, local escalation of privilege bugs.
Of course, it is safer to run as a standard account to help reduce the chance that malicious software can corrupt or modify the operating system (for example, installing keystroke loggers or
rootkits). Remember that running as a standard user does not prevent malicious software
from copying itself to locations controlled by this user, such as the users profile directory. Nor
does running as a standard user prevent malicious software from accessing and possibly copying private data that can only be accessed by the user. Running as a standard user is very
important to the health of the computer, but it is not a panacea.

Starting at the BeginningUser Tokens


When a user logs on to a Windows computer, a token is created for that user account and the
token is associated with all processes started by that user. The token includes information
such as:

The accounts security ID (SID)

Group membership (represented by SIDs)

Privileges

Token type

Impersonation level

The following code snippet shows how to access the token of the current process from C or
C++:
HANDLE hToken = NULL;
BOOL f = OpenProcessToken(GetCurrentProcess( ),TOKEN_READ,&hToken);
if (f && hToken) {
// Cool, we have the token
} else {
printf("Error getting token. Err=%d\n",GetLastError( ));
}
if (hToken) {
CloseHandle(hToken);
hToken = NULL;
}

You can get the token of another process with code such as this as long as you know the process identity (the PID) and have the necessary rights to the process and token.
HANDLE h = NULL, hToken = NULL;
if ((h = OpenProcess(PROCESS_QUERY_INFORMATION,0,pid)) &&
OpenProcessToken(h,TOKEN_QUERY,&hToken))
// success
else

16

Writing Secure Code for Windows Vista


// failure
if (h) CloseHandle(h);
if (hToken) CloseHandle(hToken);
}

If the process is running as a different user account and you dont have access, you will need
to enable the debug privilege (SE_DEBUG_NAME) using AdjustTokenPrivileges prior to calling
OpenProcess.
The following code shows how to get the current process token using .NET 1.0:
using System.Security;
using System.Security.Principal;
...
try {
WindowsIdentity id = WindowsIdentity.GetCurrent();
IntPtr token = id.Token;
// Cool, we have the token
} catch (SecurityException e) {
Console.WriteLine(e.Message);
}

You can view some of the information in a processs token in Windows Vista using the whoami
/fo list /all command, which will produce output like this:
USER INFORMATION
---------------User Name: homecomputer\toby
SID:
S-1-5-21-2014314949-3535451937-4269012161-1002
GROUP INFORMATION
----------------Group Name: Everyone
Type:
Well-known group
SID:
S-1-1-0
Attributes: Mandatory group, Enabled by default, Enabled group
Group Name:
Type:
SID:
Attributes:

BUILTIN\Users
Alias
S-1-5-32-545
Mandatory group, Enabled by default, Enabled group

<snip>
Group Name:
Type:
SID:
Attributes:

Mandatory Label\Medium Mandatory Level


Unknown SID type
S-1-16-8192
Mandatory group, Enabled by default, Enabled group

PRIVILEGES INFORMATION
---------------------Privilege Name: SeShutdownPrivilege
Description:
Shut down the system
State:
Disabled

Chapter 2

User Account Control, Tokens, and Integrity Levels

17

Privilege Name: SeChangeNotifyPrivilege


Description:
Bypass traverse checking
State:
Enabled
Privilege Name: SeUndockPrivilege
Description:
Remove computer from docking station
State:
Disabled
Privilege Name: SeIncreaseWorkingSetPrivilege
Description:
Increase a process working set
State:
Disabled
Privilege Name: SeTimeZonePrivilege
Description:
Change the time zone
State:
Disabled

The token is for a normal user account, named Toby, and as you can see, the users token is
not bristling with dangerous privileges.
You can use a tool such as Process Explorer to spelunk the token associated with a running
process. The screen shot on the next page is an example from a process running as Toby.
More Info

The Windows Vista development team adopted personas to represent the core
customers for the operating system. The three most well known are two consumers and one
IT professional. The two consumers are Abby Salazar, a mother in the home, and Toby
Salazar, Abbys son. The IT professional persona is Ichiro. The personas are concrete representations of target customers and help guide the development team when making hard
design and feature decisions.

The users token is associated with every process the user executes, and the token is used by
the operating system to make all access and privilege decisions. By default, every thread that
starts within the process also gets the token, although this can be replaced using impersonation APIs such as ImpersonateNamedPipeClient or SetThreadToken.
When a protected resource (for example, a file, shared memory, or a registry key) is accessed
by a running process, Windows will compare the access control list (ACL) on the object with
the thread token to determine if access should be granted or not. The Windows access control
model is explained in detail in Microsoft Windows Internals, 4th ed. (Russinovich 2005).
More Info

To be more precise, a thread normally does not have a token at allaccess is


checked against the process token. A thread gets its own token only after it invokes one of
the impersonation APIs.

Tobys token is not special; any user logging on as a standard user in Windows XP or
Windows Server 2003 would see a similar token (with the exception of the new privileges
added to Windows Vista) and new SID type, the mandatory label (which is explained in more
detail in the Integrity Control section later in this chapter).

18

Writing Secure Code for Windows Vista

Figure 2-1

A process running as a normal user, which is the default in Windows Vista.

Elevating to Administrator
When a standard user attempts to perform an administrative task (for example, allow a program through the firewall), the user is prompted to enter an administrative user account name
and password. This dialog box is called the Credential Prompt. If the user does not have the
credentials for an administrator, the application fails to start.

A Slight Variant: Administrator with Approval Mode


In prior versions of Windows, an admin is an admin is an admin. In Windows Vista, this is not
necessarily true. In the interests of least privilege, even members of the local administrators
group are standard users. Using the whoami/fo list/all command yields output like this
for a user, Abby, who is a member of the local administrators group:
USER INFORMATION
---------------User Name:
homecomputer\abby
SID:
S-1-5-21-2014314949-3535451937-4269012161-1000
GROUP INFORMATION
----------------Group Name: Everyone
Type:
Well-known group
SID:
S-1-1-0
Attributes: Mandatory group, Enabled by default, Enabled group

Chapter 2

User Account Control, Tokens, and Integrity Levels

Group Name:
Type:
SID:
Attributes:

BUILTIN\Administrators
Alias
S-1-5-32-544
Group used for deny only

Group Name:
Type:
SID:
Attributes:

BUILTIN\Users
Alias
S-1-5-32-545
Mandatory group, Enabled by default, Enabled group

19

<snip>
Group Name: Mandatory Label\Medium Mandatory Level
Type:
Unknown SID type
SID:
S-1-16-8192
Attributes: Mandatory group, Enabled by default, Enabled group
PRIVILEGES INFORMATION
---------------------Privilege Name: SeShutdownPrivilege
Description:
Shut down the system
State:
Disabled
Privilege Name:
Description:
State:

SeChangeNotifyPrivilege
Bypass traverse checking
Enabled

Privilege Name:
Description:
State:

SeUndockPrivilege
Remove computer from docking station
Disabled

Privilege Name: SeIncreaseWorkingSetPrivilege


Description:
Increase a process working set
State:
Disabled
Privilege Name:
Description:
State:

SeTimeZonePrivilege
Change the time zone
Disabled

Note again, this account is not bristling with privileges, and the administrator SID is set to deny.

What Are Deny SIDs?


The DACL in a users token can include SIDs that grant access and SIDs that deny access.
We say admins are really users because, until they elevate, the admin SID in their token
is set to deny access only and is not removed.
Why doesnt Windows simply remove SIDs from a users token? The reason is simple. In
Windows an objects ACL can include deny Access Control Entries (ACEs). A deny ACE
is an ACE that explicitly denies a user or a group access to the object. If an objects ACL
includes an ACE that allows read access for authenticated users, and if there is an ACE

20

Writing Secure Code for Windows Vista

that explicitly denies the Finance group access to the object, and if Paige is a member of
the Finance group, removing the Finance group SID from Paiges token would allow
Paige access to the objectbecause shes no longer indentified as a member of the
Finance group! However, if the Finance group SID stays in Paiges token but is set to a
deny-only SID, then she will be denied access to the object. Thus, SIDs are not removed
from tokens but are specially marked for deny only. In other words, a deny-only SID is
considered only with Deny ACEs, not with Allow ACEs.
The most common SIDs set to deny only are local administrators, backup operators,
and network operators.

The Updated Windows Vista Token Format


There are some big differences between a Window Vista token and the token format on prior versions of the operating system. When a user logs on to, say, Windows XP, the user has just one
token. In Windows Vista it is possible to have a linked token, which is also referred to as a filtered
token. Essentially, if the user is a member of the local Administrators group, two tokens are created during logon: The first is the users standard-user-level token stripped of potentially harmful
privileges with the Administrators SID set to deny only. The second token is the users full
administrative token; this is often called the elevated token or the full token. Most computer
operations use the first, less-privileged token. The full token is used only when the user elevates.
Windows Vista adds a number of new elements to a users token. We look at many of these
new features throughout this chapter.

Determining if a Process Is Elevated


You can determine if your process is running elevated or not by calling the GetTokenInformation function using new flags in Windows Vista.
BOOL IsElevated() {
BOOL fRet = FALSE;
HANDLE hToken = NULL;
if (OpenProcessToken(GetCurrentProcess(),TOKEN_QUERY,&hToken)) {
TOKEN_ELEVATION Elevation;
DWORD cbSize = sizeof TOKEN_ELEVATION;
if (GetTokenInformation(hToken,
TokenElevation,
&Elevation,
sizeof(Elevation),
&cbSize))
fRet = Elevation.TokenIsElevated;
}
if (hToken) CloseHandle(hToken);
return fRet;
}

Chapter 2

User Account Control, Tokens, and Integrity Levels

21

Companion Content The Ch02\MegaDump sample on this books companion Web site
is a more complete token analysis tool.

Important

Most applications dont need to know if they run in an elevated token process.
We found that, in almost all cases, the developer should just call IsUserAnAdmin..

If you want more detail about whether the token is elevated or not, you can use the following
code:
TOKEN_ELEVATION_TYPE ElevationType;
cbSize = sizeof TOKEN_ELEVATION_TYPE;
if (GetTokenInformation(hToken,
TokenElevationType,
&ElevationType,
sizeof(ElevationType),
&cbSize)) {
switch(ElevationType) {
case TokenElevationTypeDefault :
// do something
break;
case TokenElevationTypeFull :
// do something
break;
case TokenElevationTypeLimited :
// do something
break;
}
}

Here is a list of the three token levels that describe the relative strength of a token.

TokenElevationTypeDefault
Tokens with the default elevation do not have a linked token. Standard users (for example,
Toby) authenticate to the system and are assigned a token with a default elevation type. Their
logon session is not linked to an elevated session. The built-in Administrator account (disabled by default) may also be assigned a default elevation type if the UAC policy, Admin
Approval Mode for the built-in Administrator account is disabled.

TokenElevationTypeFull
The token has all groups and privileges enabled that are assigned to this user account. Typically, this applies to users who are members of the Administrators group, but it also applies to
a few other groups that require elevation to use full privileges, such as Backup Operators. The
users full-privilege logon session is associated with (or linked to) another logon session for
the same user with administrative groups and privileges filtered.

22

Writing Secure Code for Windows Vista

TokenElevationTypeLimited
The user is a member of the Administrators group or has administrative privileges assigned to
the user account that are filtered from the token. The limited elevation type indicates that an
associated or linked logon session is available for the same user that has all administrative
groups and privileges enabled.

How to Require an Application Run as an Administrator


If you build an application that absolutely must execute as an administrator, you can add
details to the application manifest that will cause Windows Vista to automatically display an
elevation dialog. The manifest file should include the following:
<?xml version='1.0' encoding='UTF-8' standalone='yes'?>
<assembly xmlns='urn:schemas-microsoft-com:asm.v1' manifestVersion='1.0'>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
<security>
<requestedPrivileges>
<requestedExecutionLevel level='requireAdministrator' uiAccess='false' />
</requestedPrivileges>
</security>
</trustInfo>
</assembly>

You can add a manifest file like this by following this process in Visual Studio 2005:
1. Launch Visual Studio 2005.
2. Open the project that requires elevation to run correctly.
3. Create a new XML file.
4. Add the text from the manifest to the XML file.
5. Save the file as projectname.uac.manifest alongside your project source code, where projectname is the name of your project.
6. Right-click Source Files in Solution Explorer.
7. Click Add and then click Existing item.
8. Find the manifest file and click on it.
9. Rebuild the project.
Note that when you compile the project using Visual Studio 2005, youll get a benign warning
that looks like this:
Elevate.uac.manifest : manifest authoring warning 81010002: Unrecognized Element
"requestedPrivileges" in namespace "urn:schemas-microsoft-com:asm.v3".

The manifest tool (mt.exe) included with Visual Studio 2005 does not recognize the requestedPrivileges element. But dont worry, the element is understood by Windows Vista.

Chapter 2

User Account Control, Tokens, and Integrity Levels

23

Caution

Windows XP SP2 has a bug when loading an image with an embedded manifest
that supports requestedPrivileges. This bug can cause Windows XP to crash when the manifest
is formatted in a specific manner. A bug fix is available (Microsoft 2006a).

When you run the application, you will be prompted to elevate to Administrator or prompted
to enter an administrators credentials, depending on your user account type.
Important

Applications marked to elevate will fail to load during operating system startup.

Notice the reference to requestedExecutionLevel in the manifest file; this option can be one of
three values as noted in Table 2-1.
Table 2-1

requestedExecutionLevel Manifest Options

Name

Comment

asInvoker

Runs the application as the invoking user and does not prompt for
administrator credentials or confirmation. If the user is an administrator, then the application runs as an admin.

highestAvailable

Grants the application the highest privilege available to the calling


user. If the user is an administrator, the user is prompted to elevate.
If the user is not an administrator, then the process starts asInvoker.
Use this option sparingly.

requireAdministrator

If the user is not an administrator, then the user is prompted to enter


administrative credentials. If the user is an administrator, the user is
prompted to confirm, and the users administrator privileges and
SIDs are enabled by using the linked token.

The uiAccess element in the manifest should always be false, unless your application is an
Accessibility application, in which case it is true because this setting allows the application to
bypass User Interface (UI) protection levels to drive input to higher privilege windows on the
users desktop.

The Mysterious Case of the Disappearing Elevation Prompt


Heres a little experiment. Create two accounts: the first named Abby, who is a member
of the local Administrators group; and the second, named Toby, is a member of the Users
group.
Logon as Abby, and run the Microsoft Management Console (MMC) by executing
mmc.exe. Note that youre prompted to consent before the application can start. Now
logon as Toby, and run mmc.exe. Youll notice that you are not prompted to elevate to
administrator or enter an administrators credentials. Why? The reason is that MMC is
marked to run at highestAvailable. MMC is an interesting tool because by itself it does not
need any particular privilege to run. It is just a shell and a framework that hosts other

24

Writing Secure Code for Windows Vista

components, and some of these components might require administrator privileges and
some might notbut MMC cant know which components you want to use a priori.
Because MMC doesnt have a way to elevate or restart itself, the standard user finds himself
at a disadvantage. As a normal user who wants to perform administrative tasks, the user has
to exit MMC and then explicitly start MMC as admin. For mixed-mode applications that
need both administrative and standard user actions, developers should strive to mark their
application as asInvoker and then provide an elevation path for the administrative actions.

User Interface Privilege Isolation


User Interface Privilege Isolation (UIPI) blocks lower-integrity processes from sending
most window messages (WM_, etc.) to higher-integrity processes. For example, a lowerintegrity process cannot send window messages or hook or attach to higher-priority processes. This helps mitigate shatter attacks (Wikipedia 2006) in which one process tries
to elevate privileges by injecting code into another, higher-privileged, process using window messages. A lower-privilege process cannot:

Use SendMessage or PostMessage to send most messages to higher-privilege application windows. These APIs return success but silently discard the message.

Use various hook functions, such as SetWindowsHookEx used by journal hooks to


monitor a higher privilege process. Attempting to do so will yield an access denied
error.

An additional flag in a users token (TokenUIAccess) indicates whether the application


can potentially override some UIPI restrictions. This is mainly used by digitally signed
accessibility applications located in the Windows directory because accessibility applications must access all applications to convert text on the screen to speech or provide
special user interface cues.

Make an Application Prompt for Credentials or Consent


Even without a manifest, you can also force an application to prompt for administrative credentials or consent using the ShellExecute function as shown here:
wchar_t wszDir[MAX_PATH];
GetSystemDirectory(wszDir,_countof(wszDir));
wcscat_s(wszDir,_countof(wszDir),L"\\cmd.exe");
HINSTANCE h = ShellExecute(0,
L"runas",
wszDir,
0,
0,
SW_SHOWNORMAL);

Chapter 2

User Account Control, Tokens, and Integrity Levels

25

Or the ShellExecuteEx function:


SHELLEXECUTEINFO sei;
sei.cbSize = sizeof(SHELLEXECUTEINFO);
sei.fMask = NULL;
sei.hwnd = NULL;
sei.lpVerb = L"runas";
sei.lpFile = L"cmd.exe";
sei.lpParameters = NULL;
sei.lpDirectory = NULL;
sei.nShow = SW_MAXIMIZE;
sei.hInstApp = NULL;
ShellExecuteEx(&sei);

If you are using Microsoft PowerShell, you can start an elevated application using this syntax:
(new-object com shell.application)
.shellexecute("cmd.exe",$null,$pwd.path,"runas",1)

Or, from the Windows Script Host (WSH), you can use this syntax:
var cmd = "cmd.exe";
var args = "";
new ActiveXObject("Shell.Application").ShellExecute(cmd, args, "", "runas");

If you program in C# or another .NET language, you can use code like this:
Process p = new Process();
ProcessStartInfo psi = new ProcessStartInfo(@ "cmd.exe");
psi.UseShellExecute = true;
psi.Verb = "runas";
p.StartInfo = psi;
p.Start();

If you want to run elevated script commands, it is highly recommended that you do so from
an elevated command window.

Starting COM Components with the COM Elevation Moniker


The example code just shown illustrates how you can start a new elevated process. But what
if you dont want to launch a new process? Lets say you only want to launch an elevated dialog box. As an example of what we mean, perform these steps:
1. Click the Date and Time applet in the Windows Vista Taskbar.
2. Click Change date and time settings.
3. Click Change date and time; note the elevation shield on the button.
4. Enter the administrators credentials, or click Continue to consent.
When the Date and Time Settings dialog box pops up, this is not a separate process, its a
COM object with a dialog box for its UI. The Date and Time applet is running as a normal
user, but the Date and Time Settings dialog is running as an administrator, because setting the
date or time is a privileged operation, requiring the SE_SYSTEMTIME_NAME privilege. This is
all performed using a new feature in Windows Vista called the COM Elevation Moniker.

26

Writing Secure Code for Windows Vista

The following code shows how you can use this feature:
HRESULT CoCreateInstanceElevated(
__in_opt
HWND
hwndParent,
__in
REFCLSID
rclsid,
__in
LPCWSTR
lpwszElevationType,
__in
REFIID
riid,
__deref_out_opt PVOID
*ppv) {
wchar_t wszCLSID[64];
wchar_t wszMonikerName[128];
*ppv = NULL;
if (0 == StringFromGUID2(rclsid, wszCLSID, _countof(wszCLSID)))
return E_OUTOFMEMORY;
int err = swprintf_s(wszMonikerName,
_countof(wszMonikerName),
L"Elevation:%s!new:%s",
lpwszElevationType,
wszCLSID);
if ( -1 == err)
return HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
BIND_OPTS3 bo;
ZeroMemory(&bo, sizeof(bo));
bo.cbStruct
= sizeof(bo);
bo.hwnd
= hwndParent;
bo.dwClassContext = CLSCTX_LOCAL_SERVER;
return CoGetObject(wszMonikerName, &bo, riid, ppv);
}

The first argument to CoGetObject is the moniker, which contains information that uniquely
identifies a COM object. The format for an elevation moniker is:
Elevation:Administrator!new{GUID}

or
Elevation:Highest!new{GUID}

Administrator maps to requireAdministrator and Highest maps to highestAvailable. You can also
replace !new with lclsid; the difference is !new will call IClassFactory::CreateInstance automatically but using !clsid does not.
Warning

Both the COM client and the COM server must be configured correctly to support elevation, which rules this technology out as a way to provide application compatibility.
For a full explanation of the settings and much more information, please refer to The COM
Elevation Moniker (MSDN 2006a). An elevated COM object represents a security boundary
and must not blindly expose administrator functionality to a client. A client may be under the
control of rogue software and may use different functions and parameters than the user
intended. To protect against this, the object should be driven solely through a user interface
that it presents to the user. Failure to do so might allow rogue software to elevate.

Chapter 2

User Account Control, Tokens, and Integrity Levels

27

Starting Elevated Managed Code Applications


On his blog (Wille 2007), Christophe Wille offers some sample code to start elevated managed code components that can be called through a normal method call or through reflection.

User Interface Considerations


The most important security-related user interface change in Windows Vista is the addition of
the shield icon. You can load the shield icon into your application with this code:
#include "shellapi.h"
SHSTOCKICONINFO si = {0};
si.cbSize = sizeof(si);
HRESULT hr = SHGetStockIconInfo(
SIID_SHIELD,
SHGSI_ICON | SHGSI_LARGEICON,
&si);

You can also load the small shield icon by setting the second argument to SHGSI_ICON |
SHGSI_SMALLICON.
You should use the shield icon in user interface elements to indicate to the user which operations require elevation. For example, if an elevated action is to be performed after pressing
a button, then the button should display the shield icon. If the process is already elevated,
then there should be no shield icons displayed at all. The simplest way in a native application to mark a button as requiring elevation is to use the Button_SetElevationRequiredState
macro:
CWnd *pBtn = GetDlgItem(IDC_BACKUP_FILES);
Button_SetElevationRequiredState(pBtn->GetSafeHwnd(),!IsElevated( ));

IsElevated is a function shown in the section Determining if a Process Is Elevated, earlier in


this chapter. The last argument to Button_SetElevationRequiredState is a Boolean argument that
determines whether or not to display the shield icon.
Figure 2-2 is a screen shot that shows the icon on a button.

Figure 2-2

A window showing the elevation shield. When the user clicks this button, she is
prompted to elevate, and then an elevated process is launched.

When a user clicks a button that starts an elevated task, you can start the task as either an elevated process, or better yet, an elevated COM object that displays a dialog box.

28

Writing Secure Code for Windows Vista

Virtualization
Before we describe virtualization, we want to point something out. Virtualization is intended
only as a bridge to assist with migration of legacy applications, and developers should not
take advantage of it for new applications. Applications that require virtualization to work correctly will not be logo-certified for Windows Vista, and virtualization is not supported for
native Windows 64-bit applications.
With that out of the way, virtualization is a feature that allows a legacy application to run as a
normal user, when normally it would fail if the application were not run by an administrator.
The biggest reason, by far, that applications fail to run as a user is that the application attempts
to write configuration or application-specific data to protected locations of the operating system.
Warning

Applications that allow virtualization are potentially attackable by other standard


user applications because they can share relatively weakly ACLd shared folders. To disable
virtualization, see the section titled, How to Disable Virtualization for Your Application later
in this chapter.

The following code will fail unless it is run by an administrator or Power User on Windows XP
SP2 because its trying to write to the Program Files directory. Yet it runs correctly on Windows Vistaas long as its a 32-bit process executed by a normal user:
wchar_t wszPath[MAX_PATH];
if (SUCCEEDED(SHGetFolderPath(NULL,
CSIDL_PROGRAM_FILES,
NULL,
0,
wszPath))) {
PathAppend(wszPath, L"Savedgame.xml");
HANDLE hFile = CreateFile(
szPath,
GENERIC_WRITE | GENERIC_READ,
0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (hFile == INVALID_HANDLE_VALUE ) {
// failed
} else {
// success
CloseHandle(hFile);
hFile = NULL;
}
}

This code works correctly on Windows Vista because application file and registry writes are virtualized by the operating system; write operations to protected locations (in this case, the Program Files directory) are redirected. If you look in the Program Files directory after running this

Chapter 2

User Account Control, Tokens, and Integrity Levels

29

application, you will see no file. So where is the file? Take a look in the C:\Users\
username\AppData\Local\VirtualStore\Program Files folder. As you can see, the file write
operation was redirected to a location the user can write to, and the application works correctly.
Tip

If you navigate using Explorer to a directory that has virtualized files, you will see the
words, Compatibility Files appear in the toolbar. If you click on this, you will see all the virtualized files.

You can see if a process is virtualized by looking in the Task Manager (see Figure 2-3). By
default the Virtualization column is not displayed, but you can display it by:
1. Launch Task Manager.
2. Click the Processes tab.
3. Click View.
4. Click Select Columns.
5. Scroll to the bottom of the list, and enable Virtualization.

Figure 2-3

Task Manager showing which processes support virtualization.

30

Writing Secure Code for Windows Vista

You can also determine if a process is virtualized with the following code:
bool IsProcessVirtualized(__out bool& fVirt) {
HANDLE hToken = NULL;
bool fRet = false;
if (!OpenProcessToken(GetCurrentProcess( ),TOKEN_QUERY,&hToken))
return fRet;
DWORD IsVirtualized = 0;
DWORD cbLen = 0;
if (GetTokenInformation (
hToken,
TokenVirtualizationEnabled,
&IsVirtualized,
sizeof IsVirtualized,
&cbLen)) {
fVirt = !!IsVirtualized;
fRet = true;
}
if(hToken)
CloseHandle(hToken);
return fRet;
}

Virtualization is intended only to enhance application compatibility with existing programs.


Applications designed for Windows Vista should not perform writes to system locations, nor
should they rely on virtualization to provide redress for incorrect application behavior.
Tip

You can look at important virtualization events in the Event Viewer. Open the Event
Viewer, and expand Applications and Services Logs, then expand Microsoft, then expand
Windows, and finally expand UAC-FileVirtualization.

When updating existing code to run on Windows Vista or writing new code for Windows
Vista, developers should ensure that, during run time, applications only store user data under
the locations noted in Table 2-2.
Table 2-2

UAC-Friendly Storage Locations for User Data

Directory

Environment
Variable

SHGetKnownFolderPath
Folder ID

Purpose

C:\Users\user\AppData\Roaming %appdata%

FOLDERID_RoamingAppData Roaming
Per-user data

C:\Users\user\AppData\Local

%localappdata%

FOLDERID_LocalAppData

C:\ProgramData

%programdata% FOLDERID_ProgramData

Virtualization is enabled only if the following conditions are met:

Process is 32-bit

Process is run by an interactive user

Per-user data
Per-machine
data

Chapter 2

User Account Control, Tokens, and Integrity Levels

31

Virtualization is not enabled for:

64-bit processes

Administrator processes

Services

Impersonated callers

Application manifest that has a requestedExecutionLevel setting

How to Disable Virtualization for Your Application


Sometimes you may want to disable file and registry virtualization, perhaps for debugging reasons. Better yet, you have fixed your application so it no longer relies on virtualization. Some
customers disable virtualization to improve application manageability. There are many ways
to disable application virtualization. Well discuss some of them here.

Create a Side-by-Side Application Manifest


If the application is unsigned and has no embedded application manifest, you can create a
stand-alone application manifest file and save it next to the main executable.
Tip

Note that Visual Studio often embeds a manifest in the compiled application. You can
disable this by opening the project properties, expanding to the Manifest Tool option, clicking Input and Output, and then setting Embed Manifest to No.

If the application is named tool.exe, then save the manifest as tool.exe.manifest. The manifest
should include the following string:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
<security>
<requestedPrivileges>
<requestedExecutionLevel
level="asInvoker"
uiAccess="false"></requestedExecutionLevel>
</requestedPrivileges>
</security>
</trustInfo>
</assembly>

Use the noVirtualization shim


Microsoft has developed a series of shims that help remedy various application compatibility issues. One such shim is the noVirtualization shim available as part of the Application
Compatibility toolset, which you can download from (Microsoft 2006b).

32

Writing Secure Code for Windows Vista

Programmatically Disabling Virtualization


Adding the following code to your main function will disable virtualization for your process.
DWORD dwVirtEnabled = 0;
BOOL ret = SetTokenInformation(hTargetProcToken, TokenVirtualizationEnabled,
&dwVirtEnabled, sizeof(dwVirtEnabled));

Change the Virtualization of a Running Process


This is not recommended, but it does work if its the only means you have.

Open Task Manager.

Select the Processes tab.

Right-click the process in question.

Check or uncheck the Virtualization option.

Integrity Levels
Windows Vista is the first version of Windows to include support for integrity protection.
Integrity protection adds a layer of defense to help reduce the chance that malicious software
will damage the operating system. Integrity levels are often referred to in the various Windows
development kits as mandatory labels. It is important to point out that integrity levels dont
prevent data disclosure; a privacy leak is still a privacy leak in the face of integrity protections.
Integrity protections allow or disallow only write operations, no read operations.
Important

The goal of integrity levels is to protect the operating system from damage,
not to protect user data from disclosure.

The tenet of integrity levels is pretty simple. A process of a lower integrity level cant write to an
object of a higher integrity level. Integrity controls in Windows Vista provide assurance that processes of lower trustworthiness (that is, lower integrity) cannot modify files or system objects of
higher trustworthiness (see Figure 2-4). This is often expressed as write-down, no write-up.
In Windows Vista, all protected objects are labeled with an integrity level. Most user and system
files and registry keys on the system have a default label of medium integrity. The primary
exception is a set of specific folders and files writeable by Internet Explorer 7 at Low integrity.
Most processes run by standard users are labeled with medium integrity, and most services are
labeled with System integrity. The root directory is protected by a high-integrity label.
When a process attempts to open an object for write access, the integrity level is checked first.
If that check succeeds, then a normal DACL check is performed. The flowchart in Figure 2-5
shows the process.

Chapter 2

User Account Control, Tokens, and Integrity Levels

Write operations
High Integrity

Low Integrity

Figure 2-4

Integrity model in Windows Vista. Lower-integrity subjects cannot write to higherintegrity objects.

Start

Is process
Integrity level
>= object
Integrity
level?

Write
Operation?

Does object
DACL allow
process identity
requested
access?

Access
Granted

Access
Denied

Figure 2-5

Flowchart showing the process of determining object access in Windows Vista.

33

34

Writing Secure Code for Windows Vista

The integrity levels in Windows Vista are represented in classic, well-known SID nomenclature, as shown in Table 2-3.
Table 2-3

Integrity SIDs

Integrity Levels

SID

Low integrity (LW)

S-1-16-4096

Medium integrity (ME)

S-1-16-8192

High integrity (HI)

S-1-16-12288

System integrity (SI)

S-1-16-16384

Note

It is possible to define custom integrity levels; for example, S-1-16-8200 is between


medium and high integrity. But to keep this chapter simple and sane, we focus only on the
four standard integrity levels. In fact, you should just stick to these basic four integrity levels!

If you look at the output from whoami earlier in this chapter you will see the following entry:
Group Name:
Type:
SID:
Attributes:

Mandatory Label\Medium Mandatory Level


Unknown SID type
S-1-16-8192
Mandatory group, Enabled by default, Enabled group

As you can see, the SID in the token shows that this process is running at medium integrity.
And yes, Unknown SID type is a bug; it should read Mandatory SID type.
Process Explorer also shows the integrity level for the application as shown in Figure 2-6.
When a user elevates to administrator, the integrity label included in the full-privilege token is
a high-integrity level label.

Figure 2-6

By default, all processes run at a medium-integrity level; this screen shot shows a
process running at medium.

Chapter 2

User Account Control, Tokens, and Integrity Levels

35

You can experiment with integrity levels with the following code, which will run a process at
low-integrity level:
DWORD err = 0;
HANDLE hToken = NULL;
HANDLE hNewToken = NULL;
PROCESS_INFORMATION ProcInfo = {0};
PSID pIntegritySid = NULL;
try {
if (!OpenProcessToken(
GetCurrentProcess( ),
TOKEN_QUERY | TOKEN_DUPLICATE,
&hToken)) {
wprintf(L"OpenProcessToken failed (%d)\n", GetLastError( ));
throw GetLastError( );
}
TOKEN_ELEVATION_TYPE ElevationType;
DWORD cbSize = sizeof TOKEN_ELEVATION_TYPE;
if (GetTokenInformation(hToken,
TokenElevationType,
&ElevationType,
sizeof(ElevationType),
&cbSize)) {
if (ElevationType == TokenElevationTypeFull) {
throw ERROR_ACCESS_DENIED;
}
} else {
wprintf(L"GetTokenInformation failed (%d)\n", GetLastError());
throw GetLastError( );
}
if (!DuplicateTokenEx(
hToken,
TOKEN_ALL_ACCESS,
NULL,
SecurityImpersonation,
TokenPrimary,
&hNewToken)) {
wprintf(L"DuplicateTokenEx failed (%d)\n", GetLastError());
CloseHandle(hToken);
hToken = NULL;
throw GetLastError();
}
if (!ConvertStringSidToSid(
L"S-1-16-4096",// Low integrity SID
&pIntegritySid)) {
wprintf(L"ConvertStringSidToSid failed (%d)\n", GetLastError( ));
throw GetLastError( );
}
TOKEN_MANDATORY_LABEL til = {0};
til.Label.Attributes = SE_GROUP_INTEGRITY;
til.Label.Sid = pIntegritySid;

36

Writing Secure Code for Windows Vista


if (!SetTokenInformation(
hNewToken,
TokenIntegrityLevel,
&til,
sizeof(TOKEN_MANDATORY_LABEL) + GetLengthSid(pIntegritySid))) {
wprintf(L"SetTokenInformation failed (%d)\n", GetLastError());
throw GetLastError( );
}
STARTUPINFO StartupInfo = {0};
StartupInfo.cb = sizeof(STARTUPINFO);
if (!CreateProcessAsUser(
hNewToken,NULL,
wszProcessName,
NULL,NULL,
FALSE,
CREATE_NEW_CONSOLE,
NULL,NULL,
&StartupInfo,&ProcInfo)) {
wprintf(L"CreateProcessAsUser failed (%d)\n", GetLastError());
throw GetLastError();
}
} catch (DWORD dwErr) {
err = dwErr;
}
if (hToken) CloseHandle(hToken);
if (hNewToken) CloseHandle(hNewToken);
if (ProcInfo.hProcess) CloseHandle(ProcInfo.hProcess);
if (ProcInfo.hThread) CloseHandle(ProcInfo.hThread);
if (pIntegritySid) LocalFree(pIntegritySid);
return err;

You can create a low-integrity SID using ConvertStringSidToSid as shown in the sample code, or
use the following code:
SID LowIntegritySid = {
SID_REVISION, 1,
{SECURITY_MANDATORY_LABEL_AUTHORITY},
SECURITY_MANDATORY_LOW_RID;

Companion Content This books companion Web site includes a sample application
named SetMIC in the Ch02 folder to start a process at an equal or lower integrity level than
the user.

Important

Note that in the sample code we reject the request to launch an application if
the user has a full admistrative token. Doing so can lead to a potential elevation of privilege
vulnerability because the spawned process would be a low-integrity process running as an
administrator. You can spawn a low-integrity process from a high-integrity process, so long
as the high-integrity process is not executing with a full token.

Chapter 2

User Account Control, Tokens, and Integrity Levels

37

As a test, log on as an administrator, start a command shell at low integrity with the SetMIC
tool, and then try writing to the root directory with the following command:
echo "Hello, World!" > c:\test.txt

It will fail because the process performing the write operation is of a lower integrity level than
the object being written to (low versus high). Note that an account cannot create a process at
a higher integrity level than its own integrity level. If you attempt to do so, the call to SetTokenInformation will fail, and GetLastError will return 1314 (privilege not held) unless the process
identity has the SE_RELABEL_NAME privilege enabled.

Where Can a Low-Integrity Process Write?


Of course, a low-integrity process can successfully write to very few locations. You can store
user-specific data in %userprofile%\AppData\LocalLow; the following code shows how to get
this directory:
#include "shlobj.h"
#include "knownfolders.h"
wchar_t *wszPath;
if (SHGetKnownFolderPath(
FOLDERID_LocalAppDataLow,
KF_FLAG_DEFAULT_PATH,
NULL,
&wszPath) == S_OK) {
// path is in wszPath
CoTaskMemFree(wszPath);
}

Setting Integrity Labels on Objects


You can also create a new object, such as a file, directory, registry key, named pipe, or shared
memory at a specified integrity level. The integrity level for an object is set using a new label
format for a system ACL (SACL).
If you are familiar with the Security Descriptor Definition Language (SDDL) (Microsoft
2006c), then you already know how to compose an integrity ACE. The SDDL format for an
integrity label is:
S:flags(ML;inheritance;mask;;;level)

S means a SACL.

The flags option describes optional control flags that indicate various protection and
inheritance options.

ML means mandatory label ACE type.

The inheritance option describes optional flags that control inheritance and inheritance
propogation.

38

Writing Secure Code for Windows Vista

The mask value is one of the following: NW (No-Write up), NR (No-Read up), or
NX (No-Execute up). The most common is NW. These settings are explained a little
later.

The level value is the actual integrity level: LW, ME, HI or SI for low, medium, high, and
system, respectively.

The following code shows how to set a No-Write up (NW), medium integrity level (ME) for an
object, in this case a file.
SECURITY_ATTRIBUTES sa = {0};
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
wchar_t *wszSacl = L"S:(ML;;NW;;;ME)";
if (ConvertStringSecurityDescriptorToSecurityDescriptor(
wszSacl,
SDDL_REVISION_1,
&(sa.lpSecurityDescriptor),
NULL)) {
wchar_t *wszFilename = L"c:\\files\\foo.txt";
HANDLE h = CreateFile(wszFilename,
GENERIC_WRITE,0, &sa,
CREATE_ALWAYS, 0,NULL);
LocalFree(sa.lpSecurityDescriptor);
if (INVALID_HANDLE_VALUE == h) {
wprintf(L"CreateFile failed (%d)", GetLastError( ));
} else {
CloseHandle(h);
h = NULL;
}
} else {
wprintf(L"SDDL Conversion failed (%d)", GetLastError( ));
}

You can look at or set the integrity level of a directory or file on an NTFS volume in Windows
Vista with the icacls command. For example, the following command shows that the
C:\Users\username\AppData\LowLocal folder used by Internet Explorer in protected mode
is set to low integrity:
C:\Users\michael\AppData>icacls LocalLow
LocalLow CONTOSO\Michael:(I)(OI)(CI)(F)
NT AUTHORITY\SYSTEM:(I)(OI)(CI)(F)
BUILTIN\Administrators:(I)(OI)(CI)(F)
Mandatory Label\Low Mandatory Level:(OI)(CI)(NW)

You can set the integrity level of a file or directory using the /setintegritylevel argument.
Note

Remember, if no explicit integrity label SID exists in a process token, or on an object,


then that object is medium integrity.

Chapter 2

User Account Control, Tokens, and Integrity Levels

39

Note that objects created by a high-integrity-level subject are medium-integrity-level by


default. This was done as an application compatibility mechanism. For instance, to enable file
sharing between medium and high; if a high-integrity-level notepad saves a text file in the
users profile, a medium-integrity-level process should be able to modify it. To keep some protection, objects created by a high-integrity-level subject are owned by the Administrators
group.

Determining an Objects Integrity Level


You can determine the integrity level of a process with the following code. There really should
be no reason to do this other than for troubleshooting, but we added it for completeness.
DWORD GetProcessIntegrityLevel(wchar_t __out_ecount_z(cbIl) *wszIl,
size_t cbIl) {
if (!wszIl) return 0xffffffff;
memset(wszIl,0,cbIl);
DWORD err = 0;
try {
HANDLE hToken = NULL;
if (!OpenProcessToken(GetCurrentProcess( ), TOKEN_QUERY, &hToken))
throw GetLastError( );
DWORD cbBuf = 0;
if (GetTokenInformation(hToken,TokenIntegrityLevel,NULL,0,&cbBuf) != 0)
throw GetLastError( );
TOKEN_MANDATORY_LABEL * pTml =
reinterpret_cast<TOKEN_MANDATORY_LABEL*> (new char[cbBuf]);
if (pTml &&
GetTokenInformation(
hToken,
TokenIntegrityLevel,
pTml,
cbBuf,
&cbBuf)) {
CloseHandle(hToken);
hToken = NULL;
DWORD ridIl = *GetSidSubAuthority(pTml->Label.Sid, 0);
if (ridIl < SECURITY_MANDATORY_LOW_RID)
wcscpy_s(wszIl,cbIl,L"?");
else if (ridIl >= SECURITY_MANDATORY_LOW_RID &&
ridIl < SECURITY_MANDATORY_MEDIUM_RID)
wcscpy_s(wszIl,cbIl,L"Low");
else if (ridIl >= SECURITY_MANDATORY_MEDIUM_RID &&
ridIl < SECURITY_MANDATORY_HIGH_RID)
wcscpy_s(wszIl,cbIl,L"Medium");
else if (ridIl >= SECURITY_MANDATORY_HIGH_RID &&
ridIl < SECURITY_MANDATORY_SYSTEM_RID)
wcscpy_s(wszIl,cbIl,L"High");
else if (ridIl >= SECURITY_MANDATORY_SYSTEM_RID)
wcscpy_s(wszIl,cbIl,L"System");
if (ridIl > SECURITY_MANDATORY_LOW_RID &&

40

Writing Secure Code for Windows Vista


ridIl != SECURITY_MANDATORY_MEDIUM_RID &&
ridIl != SECURITY_MANDATORY_HIGH_RID &&
ridIl != SECURITY_MANDATORY_SYSTEM_RID)
wcscat_s(wszIl,cbIl,L"+");
delete [] reinterpret_cast<char*>(pTml);
pTml = NULL;
} else {
throw GetLastError();
}
} catch(DWORD dwErr) {
err = dwErr;
wprintf(L"Error %d",GetLastError());
} catch(std::bad_alloc e) {
err = ERROR_OUTOFMEMORY;
wprintf(L"Error %d",err);
}
return err;
}

Rules for Integrity Settings


The rules for setting object integrity levels are as follows:

A process (subject) integrity level must be equal to or higher than the integrity level of an
object to modify the object, assuming the normal NW mask is used.

The SE_RELABEL_NAME privilege is required to raise the integrity level of an object.

A process can lower the integrity level of an object for which it can obtain modify access.

When a server impersonates a client on the same machine, the integrity level in the
impersonation token is the same as the integrity level of the client process.

The NW, NR, and NX Masks


If you look at the SDDL representation of an integrity ACE, you will notice that ACE often
includes NW, which means No-Write up in the integrity mask. Two other integrity label access
masks exist: NR (No-Read up) and NX (No-Execute up). These are broader access policies. For
example, a low-integrity process cannot read an object, such as a file, labeled S:(ML;;NR;;;ME),
and a low-integrity process cannot read or execute a file labeled S(ML;;NXNR;;;ME).
The security experts reading this are probably thinking, Isnt this the Biba integrity model or
Bell-Lapadula? The answer is no. We explored various security models a few years ago, but
found they were not appropriate as defined to the highly interactive and general-purpose environment in which Windows Vista is used. So we decided develop a modelwhich certainly
owes a debt to the Biba modelfocused on the integrity of the system. Thats what we have
today: a technology that has helped form the basis of UAC and Protected Mode in Internet
Explorer.

Chapter 2

Tip

User Account Control, Tokens, and Integrity Levels

41

Note that the icacls tool will only set the NW integrity mask.

A Defensive Model Using Integrity Levels


In Chapter 6, Internet Explorer 7 Defenses, we explain how Internet Explorer 7 in Windows
Vista uses integrity levels to reduce potential damage from malicious Web software. If you dig
a little deeper into the integrity model in Windows Vista, youll see a very useful defensive
model that can be applied to any software that is one socket away from the Internet. At a very
high level, the simplified Internet Explorer 7 Protected Mode model looks like the screen shot
in Figure 2-7.
Potentially, this model can be replicated to your Internet-facing application. Admittedly, its
not simple, but its a good defense. If your application is currently monolithic, you should
start by splitting the process into two logical chunks. The first process performs all the administrative tasks as well as opening the administrative communication channels, perhaps an
authenticated named pipe or TCP socket.
The administrative process then spins up the low-integrity process and opens the communication and control channel between the two processes. In some cases, you could start this new
process as a low-privilege user account, or you could strip unneeded privileges from the process as it starts up. Note that if the two processes communicate using an interprocess communication protocol (IPC) that supports ACLs (such as anonymous pipes, named pipes, or
shared memory and in Windows Vista, sockets), then you must set a low-integrity label on the
IPC object; otherwise, the low-integrity process will not be able to write to the IPC.
Companion Content The sample code Ch02\LowIntegrityPipe shows how to open a pipe
between a medium-integrity parent process and a low-integrity child process.

Low-integrity
level Internet
Explorer
Process

Read Web Site content

Control low-integrity process

Administrative
Internet
Explorer
Process

Potentially
Malicious Web Site

Figure 2-7 A high-level view of Internet Explorer 7.0 Protected Mode in Windows Vista. The process
that parses potentially malicious content runs as a low-integrity process.

42

Writing Secure Code for Windows Vista

Note that a low-integrity process can send data to a higher-privilege process listening on an
RPC or LRPC endpoint. Security-aware processes should use client impersonation to determine if the caller has sufficient access to read or modify server managed resources. Also,
because sockets dont use ACLs (other than to open the port in the first place), you can send
data from a low-integrity process to a high-integrity process using sockets.
Important

It is imperative that the higher-integrity administrative process does not render


or parse any low-integrity data that comes from the untrusted, low-integrity process. However, if a high-integrity process must parse low-integrity, then the high-integrity process must
verify the data exhaustively.

Note

Integrity controls in Windows Vista are a very useful and easy-to-use defense. If your
application is one socket away from the Internet, you should consider adding an option to
enable your application to run at low integrity. This will help isolate any potential damage an
exploit could cause. You should limit which applications run at low integrity to only critical
applications that are likely to come under attack, otherwise in a pathological case, if all applications run at low-integrity and access low-integrity resources, then all applications can compromise all data!

Debugging Application Compatibility


Issues in Windows Vista
Some applications designed to run on Windows XP do not run correctly unless the user is
an administrator. Many of these applications will run correctly on Windows Vista because
of application virtualization. However, virtualization is a short-term fix, and it only redirects
some registry and file system input/output (I/O); it doesnt solve the real problem
of the application being written poorly in the first place. To be honest, detecting why an
application fails to run correctly can be relatively difficult because it requires a good deal of
expertise to read all the event logs and error messages. Luckily, theres a tool available,
named the Standard User Analyzer (Microsoft 2006d), to make debugging your applications much easier.
When you test your application, the Standard User Analyzer will launch the application, monitor its actions, and wait for the application to close. The tool then generates a log for the application that contains eight sections as described next.

File Warnings
File warnings show file system access issues, such as trying to write to the \Windows directory. In general, file I/O issues can be fixed by writing to user-writable directories, such as anything under %userprofile%.

Chapter 2

User Account Control, Tokens, and Integrity Levels

43

Registry Warnings
Registry warnings show system registry access issues, such as trying to write to any portion of
HKLM. These issues can be fixed by writing to HKCU.

INI Warnings
INI warnings show issues using WriteProfileXXX, which were originally used for 16-bit
Windows applications, but are still used in some applications today. Calls to WriteProfileXXX
and WritePrivateProfileXXX should be replaced with modern configuration functions, such as
the registry APIs. You can also remedy profile function issues by using the IniFileMapping
registry settings (Margosis 2006).

Token Warnings
Token warnings show token checking issues, such as analyzing a process token to determine
group membership. It is generally deemed bad practice to analyze a user token to determine
access policy. Rather, you should rely on the operating system to perform standard access
checks when it accesses resources.

Privilege Warnings
Privilege warnings show privilege issues, such as enabling the Debug Privilege, which is normally only accessible to administrators. Privilege issues are harder to fix, because chances are
good your application needs the privilege or privileges to operate correctly. If this is the case,
then your application is probably a good candidate to break into partswhere one or more
components perform the privileged operations and you launch these components through a
COM moniker or an elevated process.

Name Space Warnings


Name space warnings show issues that relate to an application creating system-wide objects,
such as events and shared memory. The most common error is calling CreateFileMapping("Global\\objectname") because by default only administrators and service accounts can
create global objects. The easiest fix is to remove the Global reference.

Other Objects Warnings


Other objects warnings show issues relating to non-file and non-registry objects, such as
attempting to open the Service Configuration Manager (SCM) for all access with a call to
OpenSCManager(. . .,SC_MANAGER_ALL_ACCESS).

Process Warnings
If you call CreateProcess or CreateProcessAsUser on an executable that is manifested as
RequireAdministrator or is flagged as an installer by Vista, your code will receive an

44

Writing Secure Code for Windows Vista

ERROR_ELEVATION_REQUIRED (740) error. ShellExecute will behave as you expect and


prompt for elevation. As mentioned earlier in this chapter, ShellExecute allows you to define a
runas verb, which will prompt for elevation.

The Importance of Code Signing


Signing your code, especially setup code, is critical for creating a friendly experience for your
customers. Windows Vista has the ability to prevent unsigned applications from launching
with a full administrator access token. You can check this option, and the other UAC options,
by performing these steps:
1. Run gpedit.msc.
2. Confirm consent to run the application.
3. In Group Policy (it might say Local Computer Policy), expand Computer Configuration,
then expand Security Settings and Local Policies, and finally expand Security Options.
4. Scroll to the bottom of the list, and youll see a series of options prefixed with
User Account Control.
5. Right-click the security setting that youd like to view or change.
If the User Account Control: Only elevate executables that are signed and validated is
enabled, then only digitally signed applications can elevate to administrator. So, if you want
your application to operate correctly in locked-down environments, while displaying a more
user-friendly user interface, it should be signed with an Authenticode signature.
Signing and Checking Code with Authenticode at (MSDN 2002) explains the steps required
to digitally sign your code.

Privileges New to Windows Vista


All versions of Windows (and Windows Vista is no exception) have added new privileges to
mitigate new threats or to provide a protection mechanism for new functionality. In Windows,
privileges can be represented by an index or a string constant. Chapter 5, Creating Secure
and Resilient Services, describes all the privileges in Windows Vista and the following lists
the index and string constant for the privileges new to Windows Vista.

SE_TRUSTED_CREDMAN_ACCESS_NAME
(SeTrustedCredManAccessPrivilege)
SE_TRUSTED_CREDMAN_ACCESS_PRIVILEGE (31L)
This privilege is used by Credential Manager during Backup/Restore. No accounts should
have this privilege because it is only assigned to Winlogon. Users saved credentials might be
compromised if this privilege is given to other entities.

Chapter 2

User Account Control, Tokens, and Integrity Levels

45

SE_RELABEL_NAME (SeRelabelPrivilege)
SE_RELABEL_PRIVILEGE (32L)
Granted to no accounts by default, this privilege allows a user to set any integrity level, potentially violating the No-Write up integrity rule.

SE_INC_WORKING_SET_NAME (SeIncreaseWorkingSetPrivilege)
SE_INC_WORKING_SET_ PRIVILEGE (33L)
Granted to all users by default, this privilege allows a principal to increase the working set for
a process.

SE_TIME_ZONE_NAME (SeTimeZonePrivilege)
SE_TIME_ZONE_ PRIVILEGE (34L)
Granted to all users by default, this privilege allows a user to set the computers time zone, but
not the system time.

SE_CREATE_SYMBOLIC_LINK_NAME
(SeCreateSymbolicLinkPrivilege)
SE_CREATE_SYMBOLIC_LINK_ PRIVILEGE (35L)
This privilege determines if the user can create a symbolic link. Symlinks have been a source
of many Mac OS X, Linux, and Unix security bugs in the past [(CVE-2005-2714), (CVE-20061247), and (CVE-2006-4124)]. The mklink command requires this privilege, which is granted
only to administrators by default.

Call to Action

Windows Vista is here, and user accounts are no longer administrators by default, so
make sure your application runs correctly as a standard user.

Do not, under any circumstances, recommend that your customers disable UAC.

If your application runs successfully as a normal user account simply because of folder
and registry virtualization, you should plan to fix your code as soon as possible, because
virtualization will be removed eventually.

Do not use the fact that your application can write to the Program Files directory as a
sign your application is running as an administrator or power user. It was true in most

46

Writing Secure Code for Windows Vista

cases in Windows XP that a user writing the Program Files was an elevated user, but it
is not the case in Windows Vista because of virtualization, because virtualization only
applies to non-administrator processes.

It is highly recommended that you download the Standard User Analyzer tool, run your
application through it, and triage the output. Any warning could indicate issues that may
make your application fail to run correctly as a low-privilege user.

If your application is one socket away from the Internet, consider lowering the integrity
level of the process to Low.

Digitally sign your application.

References
Russinovich, Mark, and David Solomon. Microsoft Windows Internals
4th Edition. Redmond, WA: Microsoft Press, 2005.

(Russinovich 2005)

(Microsoft 2006a) The computer may restart when you add a manifest that has the

Windows Vista extension to an .exe file or to a .dll file in Windows XP Service Pack 2
(SP2), http://support.microsoft.com/Default.aspx?kbid=921337. October 2006.
The COM Elevation Moniker, http://msdn2.microsoft.com/en-us/library/
ms679687.aspx. MSDN 2006.

(MSDN 2006a)

The COM Elevation Moniker, http://msdn2.microsoft.com/en-us/library/


ms679687.aspx. MSDN 2006.

(Wille 2007)

http://chrison.net/UACElevationInManagedCodeANETCOMComponentElevated.aspx.
February 2007.
Application Compatibility Tools, http://technet.microsoft.com/en-us/
windowsvista/aa905078.aspx.

(Microsoft 2006b)

Security Descriptor Definition Language, http://msdn2.microsoft.com/


en-us/library/aa379567.aspx.

(Microsoft 2006c)

Microsoft Standard User Analyzer, http://www.microsoft.com/


downloads/details.aspx?FamilyID=DF5.

(Microsoft 2006d)

9B474-C0B7-4422-8C70-B0D9D3D2F575 or http://tinyurl.com/ymnqua. September


2006.
(CVE-2006-1247) Common Vulnerabilities and Exposures. Rm_mlcache_file in AIX 5.1.0

and AIX 5.3.0 allows local users to overwrite arbitrary files, http://cve.mitre.org/cgi-bin/
cvename.cgi?name=CVE-2006-1247.
(CVE-2005-2714) Common Vulnerabilities and Exposures. Passwd in Directory Services in

Mac OS X 10.3.x allows local users to overwrite arbitrary files, http://cve.mitre.org/


cgi-bin/cvename.cgi?name=CVE-2005-2714.

Chapter 2

User Account Control, Tokens, and Integrity Levels

47

Common Vulnerabilities and Exposures. Rm_mlcache_file in AIX 5.1.0


and AIX 5.3.0 allows local users to overwrite arbitrary files, http://cve.mitre.org/cgi-bin/
cvename.cgi?name=CVE-2006-1247.

(CVE-2006-1247)

Common Vulnerabilities and Exposures. Passwd in Directory Services in


Mac OS X 10.3.x allows local users to overwrite arbitrary files, http://cve.mitre.org/
cgi-bin/cvename.cgi?name=CVE-2005-2714.

(CVE-2005-2714)

Common Vulnerabilities and Exposures. LibXm local privilege elevation


via the DEBUG_FILE environment variable, http://cve.mitre.org/cgi-bin/
cvename.cgi?name=2006-4124.

(CVE-2006-4124)

(Wikipedia 2006)

Shatter attack, http://en.wikipedia.org/wiki/Shatter_attack.

(Margosis 2006) Margosis, Aaron. Fixing LUA bugs, Part I http://blogs.msdn.com/

aaron_margosis/archive/2006/02/16/533077.aspx. February 2006.


Signing and Checking Code with Authenticode, http://msdn.microsoft.com/
workshop/security/authcode/signing.asp.

(MSDN 2002)

Chapter 3

Buffer Overrun Defenses


In this chapter:
ASLR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .51
Stack Randomization. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .54
Heap Defenses . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .55
NX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .59
/GS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .64
SafeSEH . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .67
Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .72
Call to Action . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .72
References. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .72
Windows Vista adds several mitigations against buffer overruns and improves many of the
defenses that were already in place in Windows XP SP2 and Windows Server 2003 SP1. Before
we start discussing the new features, we need to make several important points. First, you still
have to write solid code. As we said in Writing Secure Code, all of these defenses are like the
seatbelts in your carnone of them are guaranteed to save you from your mistakes, and if you
ever have to use them, youre not having a good day (Howard and LeBlanc 2003)! Like the
seat belts (and air bags, and anti-lock brakes, etc.), no one can guarantee that youll never have
a bad day, but if you do, its always a good thing if you have something to help keep it from getting worse. Our friend Jon Pincus, a researcher in Microsoft Research, expresses this principle
very well (Jon Pincus, personal communication):
For any given mitigation, or set of mitigations, a sufficiently complex attack can overcome
the mitigations. For any given effective mitigation, there exists some set of attacks which
are stopped completely.
If you come up with some completely contrived piece of attack code with a dozen different
flaws that manages to execute arbitrary code despite all the defenses we added, you havent
discovered anything new or exciting. However, if you take a careful look at what weve done
and find room for improvement, please let us knowwere always interested in making our
platform more secure.
Figure 3-1 shows a graphic way to envision the problem.
Any piece of software will have between 5 and 50 defects per 1,000 lines of code (kloc, which
is pronounced k-loc). How to properly count software defects has been the subject of much
49

50

Writing Secure Code for Windows Vista

study and debate, and this book cant possibly address the topic thoroughly enough. A good
reference on the topic is Bugs or Defects? (Humphrey 1999). The numbers quoted here are
reasonably close to those reported by various researchers. For example, Humphrey cites
figures from three different projects from the Jet Propulsion Laboratory. Despite rigorous
development practices, from 6.5 to 9 defects/kloc were found after the programs were compiled, unit tested and integration tested. An average developer with average development practices will make 50 to 100 mistakes/kloc, many of which may be caught by compiler warnings
and testing. Code review, education, experience, and static analysis tools can drive the actual
count to the lower portion of the range. Fuzzing, or better yet, targeted test harnesses to validate the code, will also drive down the defect count. Unfortunately, you arent likely to drive
defects to zero for any non-trivial application, and the closer to zero defects you try to get, the
more expensive the code becomes to create, so it might be best to just accept that there will be
the occasional error.

Mitigations

% Exploitable Defects
Code Quality
Improvements

Defects/1000 Lines of Code

Figure 3-1

Diagram showing effect of mitigations and code improvement.

Out of the defects that do exist in the code, some will be exploitable. Even the most trivial
defenses can eliminate some attacks. For example, an off-by-one overwrite of a stack buffer
used to be typically exploitable, but with the introduction of stack protection, these are now
stopped. The techniques we discuss in this chapter are all efforts to ensure that some of the
errors that escape us dont result in an exploitable condition.
The second point wed like to make is that Microsoft didnt actually pioneer much of this, and
this text does not claim thats the case. What we are doing is delivering these features in an
extremely widely used, general-purpose operating system while doing our best to maintain
backward compatibility and good performance with an extremely wide range of applications.

Chapter 3

Buffer Overrun Defenses

51

ASLR
Address Space Layout Randomization (ASLR) is a technique that makes it more difficult for an
exploit to locate system APIs, which in turn makes it harder to leverage system APIs in exploits
to run arbitrary code. The approach involves randomizing where system libraries are loaded,
all of the starting points of the stack, and the starting points of the heaps. On a Windows XP
system, all of these are known to an attacker and may vary somewhat depending on the
service pack level of the system. There are even references available on the Web that document this information by version and service pack level.
ASLR includes randomizing all of the following elements of a running program:

Image randomization

Stack randomization

The starting address for each threads stack varies

Heap randomization

The base address for heap allocations will also vary

The addresses where the executable and DLLs are loaded varies

One common attack is to call LoadLibrary to force the application to load a DLL. The assembly
needed to do this is very trivial, and amounts to:
Push location of path buffer
Call location of LoadLibrary

Thus, if the attacker can write a path into a buffer with a known locationwhich need not
involve an overflowand then redirect execution into a spot where a very small amount of
shell code is located, your application will load a library, possibly across the network, and
invoke DllMain. As an attacker, this is a handy technique because a very complex attack can
be written in a high-level language, while the minimum size of the shell code needed becomes
very small.
ASLR can thwart such an attack by eliminating preconditions needed by the attacker. The
first problem the attacker encounters is that the address to be jumped into needs to be
known, although not exactly. If an attacker has a large buffer to work with, writing a large
number of NOP (no-op) instructions into a buffer creates a NOP slide, and the instruction
pointer only needs to be redirected to somewhere in the slide. Next, the address of the
library path needs to be known exactly, and so does the address to call the LoadLibrary function. If the starting point of the stack isnt exactly the same at all times, then finding the
buffer with the path is more difficult and so is figuring out where to find the shell code.
Finally, if LoadLibrary cant be counted on to be in the same place at all times, this will pose
additional difficulties.
Heres an application you can use to take a look at how ASLR and stack randomization work
on your system:
#include <windows.h>
#include <stdio.h>

52

Writing Secure Code for Windows Vista


unsigned long g_GlobalVar = 0;
void foo( void )
{
printf( "Address of function foo = %p\n", foo );
g_GlobalVar++;
}
int main( int argc, char* argv[ ] )
{
HMODULE hMod = LoadLibrary( L"Kernel32.dll" );
// Note this is for release builds
HMODULE hModMsVc = LoadLibrary( L"MSVCR80.dll" );
char StackBuffer[256];
void* pvAddress = GetProcAddress(hMod, "LoadLibraryW");
printf( "Kernel32 loaded at %p\n", hMod );
printf( "Address of LoadLibrary = %p\n", pvAddress );
printf( "Address of main = %p\n", main );
pvAddress = GetProcAddress( hModMsVc, "system" );
printf( "MSVCR80.dll loaded at %p\n", hModMsVc );
printf( "Address of system function = %p\n", pvAddress );
foo( );
printf( "Address of g_GlobalVar = %p\n", &g_GlobalVar );
printf( "Address of StackBuffer = %p\n", StackBuffer );
if( hMod ) FreeLibrary( hMod );
if( hModMsVc ) FreeLibrary( hModMsVc );
return 0;
}

The test app was written using the retail shipping version of Visual Studio 2005, Service Pack 1,
and the /dynamicbase linker option, released in Visual Studio 2005, Service Pack 1. Here we
find that LoadLibrary shows up in different places across reboots of the system:
First test:
Kernel32 loaded at 77AC0000
Address of LoadLibrary = 77B01E7D
Second test:
Kernel32 loaded at 77160000
Address of LoadLibrary = 771A1E7D

What is also of interest is that the location of the C runtime library doesnt changeit loads at
address 0x78130000 across both reboots. The C runtime library this application is dynamically
linked with was linked with an older linker that did not have the /dynamicbase capability, and
it wont utilize image randomization. If Id gone to the trouble to load the entire Visual Studio
update with the new C run-time DLL on my system, we wouldnt see this problem, but it does
show us something to be careful ofmany applications are built using third-party components,
and if all of the libraries your vendor supplies arent also rebuilt using the new flag, then they

Chapter 3

Buffer Overrun Defenses

53

wont be relocated and will counteract many of the benefits of ASLR. If its a library that comes
with source, be sure to rebuild it yourself to get the benefits of ASLR, although you must also be
careful to test and ensure that the change doesnt break something. Most DLLs wont be disturbed by ASLR, but this opt-in behavior is designed to keep applications from randomly breaking when upgrading to Vista.

Limitations of ASLR
ASLR is performed systemwide, once per reboot. One note is that if all of the processes using a
particular DLL unload ASLR then it would be loaded in a random place on the next load, but
many of the system DLLs are always loaded by several processes and only get randomized at
the next reboot. If youre dealing with a local attack, an attacker could easily determine
addresses, and then launch the attack. This feature helps inhibit network-based attacks, especially worms. If an application has an information disclosure vulnerability (where it reveals
exception details to an attacker) or has a format string vulnerability (which would allow the
values on the stack to be read), it may be possible for an attacker to learn the memory locations
needed to overcome this mitigation. An attacker-controller read might also be used to place
information needed for an attack into either a known location or a location with a known
offset. Another implication is that if the network service restarts itself on failure, the attacker
now has more chances to find where to call the system API, which is why we recommend that
services be configured to restart automatically a small number of times. To reduce virtual
address space fragmentation, the library is only relocated across 256 different possible load
addresses; note that the randomization is in the second-most significant byte of the address.

Performance and Compatibility Implications


One item that comes to mind immediately when thinking about relocating DLLs is that
software developers sometimes spend considerable time figuring out just where to set the
base address of a DLL, because when two DLLs try to load into the same spot (or have overlapping ranges), the last one to load is relocated to a different address. The relocation process
can be very expensive. Every fixed address in the entire DLL needs to be changed to reflect the
new starting point, so anyone concerned with load performance should try very hard to prevent relocation. If relocation is such a bad thing, then, whats the impact of randomly relocating everything?
The way ASLR is implemented deals with the performance concerns by delaying fixups until
that page of the DLL is loaded into memory. For example, Kernel32.dll exports 1,202 functions, occupying about 160 pages of memory. A typical console application might only use a
dozen or so functions exported by Kernel32.dll and would only need to fix up the pages
required to load those functions.
A second performance enhancement comes because the DLLs dont set their own addresses
any longer; Vista now packs them in with as little slack space between loaded DLLs as possible. While 2 gigabytes of address space used to seem like a lot, a modern application can often

54

Writing Secure Code for Windows Vista

use as much memory as possible. With all the DLLs being loaded into a relatively contiguous
space, theres effectively more memory available for other purposes. Having the memory
addresses relatively close to one another can sometimes help the processor cache perform
more effectively.
As implemented in Windows Vista, the compatibility implications of ASLR arent much of an
issue. Microsoft Office 2007 is a very large code base, and has a wide variety of programming
practices and techniques. When Office enabled ASLR and ran a test pass, we didnt find any substantial performance degradation, and no regressions. Although there may be things a developer could do to break themselves if ASLR were enabled, like hard-code function addresses, if all
of Office can turn this on with remarkably few problems, most apps should be in great shape.

Stack Randomization
Stack randomization changes the base address for every thread, which makes it more difficult
for an attacker to find a place to jump to within an application. For example, assume the
attacker wants to make a call to system, but the C runtime DLL is loaded in a random location
that your code also calls system. If the application code is loaded at predictable addresses, the
attacker can then just jump to where you called system yourself. Obviously, a real attack would
also include setting up arguments and buffers, and some serious mistakes would need to be
made before an attacker could have this much control.
Using the sample program listed in the ASLR section, you get the results shown in Table 3-1.
Table 3-1

Effect of Stack Randomization on Application Addresses


Original Value

After Restarting Application

Address of main

00281020

00F41020

Address of function foo

00281000

00F41000

Address of g_GlobalVar

0028336C

00F4336C

Address of StackBuffer

001EFBC4

002EF8BC

To get this protection, you have to use /dynamicbase in your linker options. Note that even
though the starting address of the executable command is randomized, the offset between the
various code elements remains constant. In this example, the offset between the entry point of
main() and foo() is 32 bytes (0x20). If you have any important information stored in global
variables, these addresses will be randomized as well. While it is generally a bad practice to
store things such as function pointers in global memory, if you do, this mitigation will make
your code more difficult to attack. Encoded pointers, which are discussed in Chapter 9, Miscellaneous Defenses and Security Technologies should also be used.
Even though the address of the stack buffers has always been somewhat unpredictable in multithreaded applications, when using this mitigation we find that the location of the stack for
the main thread is randomized; an interesting aspect to take note of is that the offset between

Chapter 3

Buffer Overrun Defenses

55

the stack and the main modules code isnt fixed from one instance of the application to the
next. If weve depriving the attackers of fixed addresses, knowledge of offsets becomes even
more important, and theres no longer a relationship between the stack addresses and the
code addresses.

Performance and Compatibility Implications


Unless you are doing something really unusual (and inadvisable), there shouldnt be any performance or compatibility issues because of randomized stack locations.

Heap Defenses
In the last several years, heap exploits have gone from exotic to typical. Countermeasures such
as /GS (explained later in this chapter) and better programming practices have made stack
overruns less frequent, but the heap is actually easier in some ways to exploit. First, the size of
the allocation is typically determined using an arithmetic calculation, and both computers
and programmers can be very bad at mathalthough computers are faster and more predictable. For a more comprehensive look at how computers can mangle integer manipulation,
take a look at Integer Handling with the C++ SafeInt Class (LeBlanc 2004), and Another
Look at the SafeInt Class (LeBlanc 2005).
To make matters worse, common behaviors for a heap make unreliable exploits work more
often. Lets say that you can get execution flow to jump into some spot in the heap, but you
cant control exactly where it will go. One obvious attack is to put an enormous amount of data
into the heap and use a very large NOP slide that causes execution of anything in the NOP slide
to run down into your shell code. It isnt always possible to put very large amounts of data into
the heap, so an alternate approach is a technique known as heap spraying, which is a technique first noted in eEyes advisory about the IDA overflow (eEye 2001), which was well
known because it was developed into the Code Red worm in 2001. Heap spraying involves
writing a large number of copies of your shell code into the heap; depending on the details of
the exploit, you would be much more likely to have the execution jump into the shell code
because large allocations would typically end up in another location. If youre faced with executing legitimate allocations, none of the defenses discussed in the remainder of this section
apply, but NX (No eXecute) will stop these attacks cold. NX will be covered in the next section.
Another problem exploits a very common programming flawdangling pointers and
double-free conditions. Mike Marcelais of the Office Trustworthy Computing team came up
with the following three common double-free conditions that can be dangerous (personal
communication):
The first common double-free problem is when the heap structures in a way that an attacker
can exploit. If the heap manager does not maintain the control data adjacent to the user data,
this attack may not be possible. The base Windows heap in Windows Vista has also been
hardened against this attackmore on this in a moment.

56

Writing Secure Code for Windows Vista

There is a pattern of alloc(a), free(a), alloc(b), free(a), alloc(c) all on the same address, as illustrated by the following code:
char* ptrA = new char[64];
// some code here
delete[ ] ptrA;
// now we need some more memory
char* ptrB = new char[64];
// Note that ptrB has the same value as ptrA
// Some more code, just to confuse things
// And now we make a mistake
delete[ ] ptrA;
// Oops! We just freed ptrB!
// Now we need more memory
char* ptrC = new char[64];
// ptrC will now be used to write memory that
// the code dealing with ptrB thinks is validated

The second condition is that efficient heap behavior reallocates recently freed memory that is
the same size. In this case, the function that requested alloc(b) has a pointer to memory controlled by the function that called alloc(c). If the attacker can control the memory written into
alloc(c), this situation is very exploitable, and there isnt anything an allocator can do to prevent this from causing problems. An obvious attack here is that function b validates user
input and copies it to allocated memory. Function c then copies something else over the
validated input, and then a subsequent operation is performed on the data in allocation b.
A third attack is a pattern of alloc(a), free(a), alloc(b), use(a), free(a), as shown here:
char* ptrA = new CFoo;
// Some code, and we then delete allocation A
delete[ ] ptrA;
// Now we need another allocation the same size
// Note that ptrA and ptrB point to the same memory
char* ptrB = new CFoo;
// Copy some data into ptrB
// Do something with ptrA, not knowing that ptrB has changed things
// If ptrA is a class, this includes calling the destructor
delete[ ] ptrA;

Note that if allocation a contains an object with a destructor, thats equivalent to using the
memory. In this case, the code using ptrB is changing the contents of the buffer pointed to by
ptrA, while ptrA is believed to have validated data. There is some potential for the usage of ptrB
to attack ptrA, and in this case, the converse is true as wellthe usage of ptrA could very easily
cause the data kept in ptrB to become invalid.
One good programming practice prevents this type of error from being exploitable: always set
pointers to null when freeing them, although this still wont help if there are multiple copies
of the same pointer. Then the use(a) step will cause a null dereference crash; in the previous
example, freeing or deleting a null pointer is benignnot only does it not crash, but the pattern of alloc(a), free(a), alloc(b), free(a), alloc(c) becomes non-exploitable as well, since calling

Chapter 3

Buffer Overrun Defenses

57

delete on a null pointer doesnt do anything, and functions b and c would then have allocations in different places. The following C++ inline functions would help:
template < typename T >
void DeleteT( T*& tPtrRef )
{
assert( tPtrRef != NULL );
delete tPtrRef;
tPtrRef = NULL;
}
// Use when allocation is new T[count]
template < typename T >
void DeleteTArray( T*& tPtrRef )
{
assert( tPtrRef != NULL );
delete[ ] tPtrRef;
tPtrRef = NULL;
}

The reason these functions must be templatized is that for delete or delete[] to properly call
object destructors, the object type must be known. A debugging assert will help catch and fix
these conditions because, at run time, the second delete will be benign and without the assert,
you wouldnt catch the double-free problem, which could be a symptom of other serious
errors. While the heap manager cant protect you against the last two problems listed here,
some of the other countermeasures might help. Our advice is that all double-free bugs should
be fixed. Another good approach is to use smart pointer classes, although the behavior of the
class must be understood before it is used.
In the case of a heap overrun, the effects depend on the heap manager being used. The
default Windows heap places control data immediately before and after every allocation, and
attackers can target both the control data and data kept on the heap in adjacent allocations.
A number of researchers have found ways to attack the default Windows heap, and improvements in the Windows Vista heap have been numerous. Heres a partial list of recent
improvements:

Checking validity of forward and back links A free block has the address of the previ-

ous and next free blocks stored immediately after the block header. Basically, the value
of the forward link turns into the value to write, and the value of the backward link is
where to write the forward link value. This leads to an arbitrary 4 bytes (on a 32-bit system) being written anywhere in memory. The change is to check that the structures at
those locations properly point back to where it started. This improvement was delivered
in Windows XP SP2.

Part of the block header is XORd with a random number, which makes determining the value to overwrite very difficult. The performance
impact is small, but the benefits are large.
Block metadata randomization

58

Writing Secure Code for Windows Vista

The previous 8-bit cookie has been repurposed to validate a


larger part of the header. Another change with low performance impact, but its difficult
to attack.

Heap base randomization This was mentioned earlier in the ASLR section.

Heap function pointer randomization Function pointers used by the heap are
encoded. This technique will be discussed at greater length in Chapter 10.

Entry integrity check

Basically, we must expect the abilities of the attackers to continue to improve, but we must
also expect the defenders to continue to improve. Any list of attacks and countermeasures we
can give you is probably going to be out of date by the time you read this book. What is important is knowing how to protect yourself and how to leverage the capabilities of the operating
system to help protect your customers.
The first heap countermeasure thats new to Windows Vista is enabling application termination on heap corruption in your application, although it is possible for the exploit to happen
before the heap manager notices corruption. In older versions of the heap, the default behavior when the applications heap became corrupt was to just to leak the corrupted memory
and keep running, even in the face of poorly behaved code. For example, heres something
guaranteed to cause problems:
char* pBuf = (char*)malloc(128);
char* pBuf2 = (char*)malloc(128);
char* pBuf3 = (char*)malloc(128);
memset(pBuf, 'A', 128*3);
printf("Freeing pBuf3\n");
free(pBuf3);
printf("Freeing pBuf2\n");
free(pBuf2);
printf("Freeing pBuf\n");
free(pBuf);

On Windows Vista, even without the heap set to terminate on corruption, this code wont get
any further than the first call to free before it causes the application to abort. On earlier versions of the operating system, including Windows Server 2003 and Windows XP, it executes
all the printf statements and exits normally. Note that this has to be tested with release builds,
because the debug heap does extra checking.
Its always better to crash than to run someone elses shell code, but your customers wont
appreciate crashing either. Enabling terminate on corruption for your processs heap should be
done early in your development cycle to give you time to shake out any previously benign
bugs. Additionally, if your application can host third-party code in some form, such as plugins, you may want to think about getting the third-party code out of your process. A surprisingly large number of the crashes in Microsoft Office and Internet Explorer are due to code
that isnt shipped by Microsoft. To enable the heap to terminate the application on corruption, simply add this code snippet to your applications main or WinMain function:

Chapter 3

Buffer Overrun Defenses

59

bool EnableTerminateOnCorrupt()
{
if( HeapSetInformation( GetProcessHeap(),
HeapEnableTerminationOnCorruption,
NULL,
0 ) )
{
printf( "Terminate on corruption enabled\n" );
return true;
}
printf( "Terminate on corruption not enabled - err = %d\n",
GetLastError() );
return false;
}

Obviously, you wouldnt leave diagnostic printf statements in your shipping code, so handle
errors however you like. Wed suggest making an unusual failure such as this an exceptionor
this could be a protection that is only enabled on Vista and just ignore errors when running
an earlier version of Windows.
An additional countermeasure is that the low fragmentation heap (LFH) is historically more
resistant to attack than the standard Windows heap. Why not use the LFH all of the time? The
answer is that heap performance is very dependent on how an application uses the heap, and
in fact, Vista may decide to use the LFH at run time if usage patterns make it beneficial. Before
shipping code with the LFH, use performance benchmarking to see if theres an improvement
or a decrease in performance. If the LFH works well with the application, heres how to enable
it:
bool EnableLowFragHeap( )
{
ULONG ulHeapInfo = 2;
if( HeapSetInformation( GetProcessHeap( ),
HeapCompatibilityInformation,
&ulHeapInfo,
sizeof( ULONG ) ) )
{
printf( "Low fragmentation heap enabled\n" );
return true;
}
printf( "Low fragmentation heap not enabled - err = %d\n",
GetLastError( ) );
return false;
}

NX
NX, short for No eXecute is known by several names. Intel calls it the Execute Disable or
XD-bit, AMD calls it Enhanced Virus Protection, and its also been written as W^X, which
translates to write or execute, but not both. Windows refers to NX as Data Execution Prevention, and the settings can be found using the System Control Panel applet, under Advanced,

60

Writing Secure Code for Windows Vista

Performance Options. Non-executable stacks and heaps arent especially newSuns Solaris
operating system had a setting to enable a non-executable stack several years ago, and OpenBSD moved to NX in OpenBSD v3.3 and later. In the Windows line of operating systems, NX
has been available since Windows Server 2003 shipped and then was back ported to
Windows XP in Service Pack 2. An indication of just how far back NX was anticipated is that
one of the flags to the VirtualProtect function, as it originally was documented back in 1993
when Windows NT 3.1 shipped, was a flag to set whether a page was executable. Since the
x86 family of processors didnt support NX on a per-page basis until recently, the flag had no
effect on x86 processors until some additional work was done to detect NX support at the
processor level (David Cutler, personal communication). It didnt have an effect on some of
the other processors originally supported by Windows NT, but it is interesting to note that the
architects of the operating system anticipated this need.
By default the majority of core operating system components support NX. You can see if a component is protected by NX by looking at the process under Vistas Task Manager; its an optional
column named Data Execution Prevention. Although the dialog box that allows you to configure
NX refers to software NX as a fallback, software NX doesnt protect much more than exception
handlers and only handles a small subset of the attacks that real hardware NX will stop.
The concept here is simple: If a page of memory, whether it is on the stack or the heap, is writable, we ought not be executing code from that page. The vast majority of the exploits seen
today will execute code from either the heap or the stack. You might wonder why NX isnt a
sufficient protection against malwaretake a look at Bypassing Windows Hardware-enforced
Data Execution Prevention (Skape and Skywing 2005).

Bypassing NX
Basically, there have to be ways to enable executable memory. One example would be
when we load a DLL after process initialization. The operating system has to allocate
pages and write the instructions into process memory, and the system expects to be able
to execute these instructions once done. If a piece of shell code could first cause VirtualProtect to be called with the correct parameters, NX is then defeated. As it turns out,
calling VirtualProtect, with all the correct parameters in place, is a little difficult due to
needing to write very arbitrary valueseven on systems without ASLR protection. Matt
Miller (aka Skape) of the Metasploit project, and Ken Johnson (aka Skywing) point out
that it is also possible to call NtSetInformationProcess to disable NX for an entire process, unless the application has been compiled with /NXCOMPAT. This functionality
allows for backward compatibility and allows an application to continue to work if it
happens to load a DLL that isnt compatible with NX protection.
As of this writing, the combination of NX and ASLR appears to stop all but the most contrived
attacks, but were not foolish enough to claim that this set of protections is invincible (and

Chapter 3

Buffer Overrun Defenses

61

most certainly not unbreakable). Lets take a look at how this feature works in a small snippet
of sample code:
#include <stdio.h>
#include <string.h>
// win32_exec - EXITFUNC=seh CMD=calc.exe Size=164
// Encoder=PexFnstenvSub http://metasploit.com
const unsigned char scode[] =
"\x33\xc9\x83\xe9\xdd\xd9\xee\xd9\x74\x24\xf4\x5b\x81\x73\x13\xc9"
"\xfa\x9b\x8c\x83\xeb\xfc\xe2\xf4\x35\x12\xdf\x8c\xc9\xfa\x10\xc9"
"\xf5\x71\xe7\x89\xb1\xfb\x74\x07\x86\xe2\x10\xd3\xe9\xfb\x70\xc5"
"\x42\xce\x10\x8d\x27\xcb\x5b\x15\x65\x7e\x5b\xf8\xce\x3b\x51\x81"
"\xc8\x38\x70\x78\xf2\xae\xbf\x88\xbc\x1f\x10\xd3\xed\xfb\x70\xea"
"\x42\xf6\xd0\x07\x96\xe6\x9a\x67\x42\xe6\x10\x8d\x22\x73\xc7\xa8"
"\xcd\x39\xaa\x4c\xad\x71\xdb\xbc\x4c\x3a\xe3\x80\x42\xba\x97\x07"
"\xb9\xe6\x36\x07\xa1\xf2\x70\x85\x42\x7a\x2b\x8c\xc9\xfa\x10\xe4"
"\xf5\xa5\xaa\x7a\xa9\xac\x12\x74\x4a\x3a\xe0\xdc\xa1\x0a\x11\x88"
"\x96\x92\x03\x72\x43\xf4\xcc\x73\x2e\x99\xfa\xe0\xaa\xd4\xfe\xf4"
"\xac\xfa\x9b\x8c";
typedef void (*RunShell)( void );
int main( int argc, char* argv[] )
{
char StackBuf[256];
RunShell shell = (RunShell)(void*)StackBuf;
strcpy_s( StackBuf, sizeof( StackBuf ), (const char*)scode );
(*shell)();
return 0;
}

This code sample is an example of just how ridiculously easy it has become for anyone to
obtain completely arbitrary shell code to do whatever they like. All it took to get this string of
shell code was to go to www.metasploit.com, download and install their framework, go to their
Web interface, and then choose from the menu items. Once compiled and run, a running
instance of the Windows calculator appears, and the application will then crash because the
shell code is written to cause an exception once the command line is executed. Another
option is to get the shell code to call ExitProcess, which will cause the application to exit
cleanly.
If /NXCOMPAT is added to the linker options, and if the system supports NX (that is, DEP or
XD), and if the demo code is run again from the development environment, a message is generated that looks like this:
Unhandled exception at 0x0012fe40 in NxTest.exe: 0xC0000005: Access violation.
A quick look at the exception address shows that 0x0012fe40 is the address of StackBuf; note
that there are no extra instances of calc.exe on the desktop. The system may indicate that the
processor doesnt support NX when there is actually a new processor that should support
NX. If thats the case, check the BIOS options. It seems that many BIOS manufacturers are

62

Writing Secure Code for Windows Vista

defaulting NX to off. If the computer does have NX disabled in the BIOS, talk to the hardware
vendor and ask that it be enabled by default for all their computers. Even with hardware NX
disabled there may still be the weaker software-based protection, which ironically enough,
wont stop the preceding example from executing because there is no buffer overrun corrupting an exception handler.
Its also interesting to see what Windows Vista does with this application when it is simply
invoked from the command line. It first tells us that NxTest.exe has stopped working. If we
then tell it to close, a help balloon pops up telling us that Data Execution Prevention has
stopped the program, which then explains that weve just stopped a security-related flaw.
You must test your application with NX enabled because your customers are going to do it for
you, sometimes without knowing what the problem could be, which is that NX is enabled
differently on the server line of operating systems and the desktop versions. On the client
versions (Windows XP and Vista), the default is that only operating system components are
opted in; no other applications have NX enabled. On the server, all applications, except those
in the opt-out list, have NX enabled. While thats the default, nervous security administrators
could change the default for clients to the setting for the servers. If this isnt tested, there could
be seemingly random failures as people upgrade to hardware that supports NX and has it
enabled in the BIOS.
Currently, the NXCOMPAT flag in the header is ignored by any Windows operating system
prior to Windows Vista. On Windows Vista, if NXCOMPAT is set in the linker options, then
the application will be running with NX regardless of the settings at OS level (once hardware
NX is available). If NXCOMPAT:NO is set, then NX will not apply to the application. Just like
ASLR and the heap settings, NXCOMPAT is set processwide; if youre hosting third-party
code, this may cause some problems and is another reason to find a way to get third-party
code into its own process.

Performance and Compatibility Implications


There is no performance impact of using NX except when an exception is raised. There could,
however, be compatibility problems, depending on how complex an application is. Note that
applications using older versions of the ATL library may have problems with NX. It is quite
typical for some applications that perform high-performance image manipulation and rendering to create assembler for the pixel pipeline on the fly. Some interpreted languages will also
compile a script into assembler and execute it. If the application allows third-party plug-ins,
but you cant be sure that all of the plug-ins are compiled with NX (or are compatible), then
you may not be able to immediately use NX in your application. If it is the application that is
creating the assembler, the work-around is to obtain a memory page for this use and call
VirtualProtect to enable execution on that page. If you can predict what assembler is needed,
then it is best to write it into memory and disable write at the same time you enable execute on
that page. If the application allows plug-ins, then the best approach is to get the plug-ins out

Chapter 3

Buffer Overrun Defenses

63

of the process. Getting other peoples code out of your process may give you some stability
benefits, assuming you write better code than they do!
Heres a handy class that you can use if you do need to execute code on the fly and would like
to do it safely:
class WriteThenExecute
{
public:
WriteThenExecute() : pMemory( NULL ),
fIsExecutable( false ),
cbMemory( 0 )
{}
~WriteThenExecute()
{
if( pMemory != NULL )
VirtualFree( pMemory, 0, MEM_RELEASE );
}
void Allocate(SIZE_T dwSize = 4096 )
{
pMemory = VirtualAlloc( NULL, dwSize,
MEM_COMMIT, PAGE_READWRITE );
if( pMemory == NULL )
throw GetLastError();
cbMemory = dwSize;
}
void CopyBytes( BYTE* pBytes, SIZE_T cbBytes )
{
if( cbBytes <= cbMemory )
{
DWORD dwPrevProtect;
CopyMemory( pMemory, pBytes, cbBytes );
if( VirtualProtect( pMemory, cbMemory,
PAGE_EXECUTE_READ, &dwPrevProtect ) )
{
fIsExecutable = true;
return;
}
throw GetLastError();
}
throw ERROR_INSUFFICIENT_BUFFER;
}
template< typename T >
T GetFunctionPtr()
{
if( fIsExecutable )
return reinterpret_cast< T >( pMemory );
return reinterpret_cast< T >( NULL );
}
private:

64

Writing Secure Code for Windows Vista


void* pMemory;
SIZE_T cbMemory;
bool fIsExecutable;
};
int main(void)
{
WriteThenExecute foo;
BYTE DemoBuffer[64];
foo.Allocate();
foo.CopyBytes( DemoBuffer, sizeof( DemoBuffer ) );
BYTE* pDemo = foo.GetFunctionPtr< BYTE* >();
}

The small main function demonstrates how you might use this class. Its fairly simplejust
allocate as much memory as youll need, copy in the assembly youd like to run, and then get
a function pointer. There are a couple of issues wed like to bring up before you put this code
into production. First, some asserts ought to be sprinkled liberally through the code. Calling
Allocate more than once will leak memory and corrupt internal state; calling CopyBytes more
than once will cause you to throw an exception; and the default copy constructor and assignment operator ought to be declared private with no implementation, because copying this
class to another instance would cause memory leaks or double-free conditions. Second, its
also a good idea to make a Release, and possibly a MakeWritable method that would reset the
class to its original state. Although we throw DWORDs as exceptions in many places in the
examples, you shouldnt do this in production codeuse std::exception, or another dedicated
exception class instead. Finally, the class isnt thread safe.

/GS
The /GS flag has been around since the release of Visual Studio 7.0. In the original approach,
it was simply a randomly generated cookie placed between the return address and the local
variables on the stack. If the EBP register was pushed onto the stack, the cookie would guard
this as well. It would stop some of the simplest attacks against simple functions, and, although
it was better than nothing, no developer should ever believe that theyre protected against
attacks merely because of /GS. Lets take a look at a sample application:
#define _CRT_SECURE_NO_DEPRECATE
#include <stdio.h>
#include <string.h>
void VulnerableFunc( const char* input, char* out )
{
char* pTmp;
char buf[256];
strcpy( buf, "Prefix:" );
strcat( buf, input );
// Transform the input, and write it to the output buffer
for( pTmp = buf; *pTmp != '\0'; pTmp++ )
{
*out++ = *pTmp + 0x20;

Chapter 3

Buffer Overrun Defenses

65

}
}
int main( int argc, char* argv[] )
{
char buf2[256];
VulnerableFunc( argv[1], buf2 );
printf( "%s\n", buf2 );
return 0;
}

Starting just after we enter main, heres the commented disassembly (my comments above the
instructions):
int main( int argc, char* argv[] )
{
// Save the previous value of the frame pointer on the stack
00411300 push
ebp
// Put the current stack pointer into the ebp register
00411301 mov
ebp,esp
// Create room for buf2
00411303 sub
esp,140h
// Save three more registers on the stack
00411309 push
ebx
0041130A push
esi
0041130B push
edi
char buf2[256];
VulnerableFunc( argv[1], buf2 );
// Get the address of buf2, and put it on the stack
0041130C lea
eax,[buf2]
00411312 push
eax
// Find the value of argv[1], also place it on the stack
00411313 mov
ecx,dword ptr [argv]
00411316 mov
edx,dword ptr [ecx+4]
00411319 push
edx
// Call VulnerableFunc, and on return, adjust the stack pointer
0041131A call
VulnerableFunc (41102Dh)
0041131F add
esp,8

Once inside VulnerableFunc, we have this:


void VulnerableFunc( const char* input, char* out )
{
// Save the previous
value of the frame pointer on the stack
00411260 push
ebp
// Put the current stack pointer into the ebp register
00411261 mov
ebp,esp
// Create room for buf and pTmp
00411263 sub
esp,144h
00411269 push
ebx
0041126A push
esi
0041126B push
edi
char* pTmp;
char buf[256];

66

Writing Secure Code for Windows Vista

In this example, all optimizations and stack checking are disabled so that you can see what typical applications used to do. In this application, the stack is shown by the diagram in Figure 3-2.

buf
pTmp
previous frame pointer
return address to caller
value of input pointer
value of out pointer
ebx, esi, and edi
registers
buf2

Figure 3-2

Stack diagram for a typical application.

Now lets look at what happens, step by step, as buf overflows. The first value to get mangled
is pTmp, but that wont get us anywhereit will just be initialized to zero and incremented as
we process the buf character array. The next value to get overwritten is the previous frame
pointer. This is interesting because on return from the second function (in this case, main),
code execution will jump into the address located here. If we had the classic off-by-one attack,
this is where the fun starts.
Next, things start to get really fun: we can now overwrite the return address and set the input and
out values to anything we like. Setting input isnt especially interestingby the time the overrun
has happened, weve already used that variable and wont write it again. The out parameter is a
real problem, because once that is overwritten the attacker can write nearly anywhere in application memory that theyd like once we fall into the for loop toward the end of VulnerableFunc.
In the original /GS implementation, a cookie was just placed between the local variables and
the stored registers (if any) and the return address. This would leave pTmp open to attack, and
although in this case, it is uninteresting, that may not always be true, especially if this were a
function pointer. In the case of a limited overwrite, it isnt possible to tamper with the previous frame pointer without detection, so /GS in its simplest incarnation would stop a simple
off-by-one (or even off-by-a-few) overflow from being exploitable. In the case of an unchecked
overrun, the attacker has the problem of having to fix up the cookie, but recall that overwriting the out pointer allows the attacker to put nearly any value he or she would like into any
memory location (although in this example, a location with any 0 bytes would be a problem).
Lets take a look at what the most recent version of /GS will do with the same function:

Chapter 3

Buffer Overrun Defenses

67

void VulnerableFunc( const char* input, char* out )


{
// Make room for the local variables
00401000 sub
esp,104h
// Copy the security cookie into eax
00401006 mov
eax,dword ptr [___security_cookie (403000h)]
// XOR the cookie with the stack pointer
0040100B xor
eax,esp
// Put the resulting cookie at the end of the buffer
0040100D mov
dword ptr [esp+100h],eax
char* pTmp;
char buf[256];
strcpy( buf, "Prefix:" );
00401014 mov
ecx,dword ptr [string "Prefix:" (4020DCh)]
// Now copy the function arguments into registers before anything can
// tamper with them.
0040101A mov
eax,dword ptr [esp+108h]
00401021 mov
edx,dword ptr [esp+10Ch]

As you can see, this implementation is much safer. The arguments to the function are either
copied into registers or are put on the stack above the buffer. Additionally, as we discuss in the
next section, if an exception were thrown inside this function, the cookie would be checked
prior to executing the exception handler.
Note

While you should always use /GS, you still need to write solid code!

SafeSEH
One of the most significant flaws in the original implementation of the /GS flag was found by
David Litchfield. In any Windows application, there will be at least one, and possibly several,
structured exception handlers (SEH). While we dont have room for a thorough review of how
exception handlers work and when you should be using them, SEH understand three keywords: __try, __except, and __finally. If youd like to learn more about exception handlers, look
up the Structured Exception Handling topic in MSDN, and one of the best explanations is
in Jeffrey Richters Advanced Windows books. Any edition will do, although unfortunately, the
books are currently out of print.
The __try keyword is almost exactly analogous to the C++ try keyword and declares that a
block of code has an exception handler. The __except keyword declares a block that behaves
similarly to a block declared with catch in C++. Unlike C++, you dont catch thrown exceptions
by type, but you can analyze the exception record to determine whether youd like to handle
the exception. You can choose to continue execution after the handler, do something to fix the
problem and resume execution, or tell it to continue to search for an applicable exception
handler. A __finally block is a way for a C program to behave very similarly to how a C++

68

Writing Secure Code for Windows Vista

application would use destructors. No matter how you exit the __try block, the __finally block
is guaranteed to be executed.
We cant say strongly enough that you need to be exceptionally careful when using SEH or
C++ exception handling. Weve both seen bad code along these lines:
__try
{
// We're not really sure if this will work
memcpy( dst, src, size );
}
__except( EXCEPTION_EXECUTE_HANDLER )
{
// I guess something went wrong. Oh well, exceptions are kewl
}

Do NOT do this in your code! This sort of code is a great way to get hacked, even if you are using
the /SafeSEH flag. So lets take a look at what can go wrong with SEH, and why it became a problem for the /GS flag. When an exception handler is registered for a block of code, an
EXCEPTION_REGISTRATION structure is pushed onto the stack. The EXCEPTION_ REGISTRATION structure contains a pointer to the next EXCEPTION_REGISTRATION structure, and
the address of the current exception handler. Although the amazingly clever Mr. Litchfield has
written a 16-page document detailing it (Litchfield 2003), the problem is essentially that you
have a function pointer sitting on the stack just waiting to get overwritten. If the attacker can
overwrite the buffer far enough, the function pointer to the current exception handler gets overwritten with the address of the attackers choice. The only thing remaining is to cause an exception before the function exits normally. This problem is why attacks that write a very large
amount of information outside of the buffer are frequently exploitable. Once the attacker provokes an exception, the exception handler is called, and because the function hasnt returned,
the security cookie isnt checked, and were now running arbitrary code. Where some of the previously reported flaws in /GS depended on contrived code with multiple problems to bypass
stack protection, this attack works regardless of the code internal to the function, as long as the
overwrite extends far enough to hit the exception handler, or is an arbitrary DWORD overwrite,
and if an exception can be caused prior to the function exiting normally. As mentioned in the
previous section, the Visual Studio 2005 compiler treats calling an exception handler as if the
function had exited (which is often the result of calling an exception handler) and checks the
security cookie prior to executing the handler. While Litchfields attack is thwarted, an arbitrary
DWORD written on top of an exception handler will still cause problems unless we use SafeSEH.
Heres an application we can use to demonstrate both the problem and the various solutions:
#define _CRT_SECURE_NO_DEPRECATE
#include <windows.h>
#include <stdio.h>
win32_exec - EXITFUNC=process CMD=calc.exe Size=164
Encoder=PexFnstenvSub http://metasploit.com
unsigned char scode[] =
"\x33\xc9\x83\xe9\xdd\xd9\xee\xd9\x74\x24\xf4\x5b\x81\x73\x13\x46"

Chapter 3

Buffer Overrun Defenses

"\x12\x29\x79\x83\xeb\xfc\xe2\xf4\xba\xfa\x6d\x79\x46\x12\xa2\x3c"
"\x7a\x99\x55\x7c\x3e\x13\xc6\xf2\x09\x0a\xa2\x26\x66\x13\xc2\x30"
"\xcd\x26\xa2\x78\xa8\x23\xe9\xe0\xea\x96\xe9\x0d\x41\xd3\xe3\x74"
"\x47\xd0\xc2\x8d\x7d\x46\x0d\x7d\x33\xf7\xa2\x26\x62\x13\xc2\x1f"
"\xcd\x1e\x62\xf2\x19\x0e\x28\x92\xcd\x0e\xa2\x78\xad\x9b\x75\x5d"
"\x42\xd1\x18\xb9\x22\x99\x69\x49\xc3\xd2\x51\x75\xcd\x52\x25\xf2"
"\x36\x0e\x84\xf2\x2e\x1a\xc2\x70\xcd\x92\x99\x79\x46\x12\xa2\x11"
"\x7a\x4d\x18\x8f\x26\x44\xa0\x81\xc5\xd2\x52\x29\x2e\x6c\xf1\x9b"
"\x35\x7a\xb1\x87\xcc\x1c\x7e\x86\xa1\x71\x48\x15\x25\x3c\x4c\x01"
"\x23\x12\x29\x79";
char* pHeapShell;
// Function to demonstrate overwriting a structured exception
// handler.
void foo( int elements )
{
char* ptr = NULL;
char buf[ 32 ];
int i;
// For loop to cause the overwrite.
// The value written into each byte is
// incremented to make it easier to determine where
// the exception handler address is located
for( i = 0; i < elements; i++ )
{
buf[i] = 0x20 + i;
// In this particular piece of code, the
// exception pointer starts at an offset of 0x30
// bytes from the start of the buffer
// Note if this is compiled with a newer
// compiler, the offset might be different
// on my pre-release version, the test should be
// for buf[i] == 0x58
if( buf[i] == 0x50 )
{
DWORD* pdw = (DWORD*)( buf + i );
// To try and execute an exception handler
// that isn't on the heap, change this to:
// *pdw = (DWORD)scode;
*pdw = (DWORD)pHeapShell;
i += 3;
}
}
buf[elements] = 0;
printf( "%s\n", buf );
//
//
//
//

The try-except block that we need to have an


exception handler nearby. Note that if we didn't have
a try-except or try-catch block of our own, there would
an exception handler for the application

69

70

Writing Secure Code for Windows Vista


__try
{
// All of this is fairly silly code
// the compiler from optimizing the
if( buf[31] == '\0' )
{
ptr = buf;
}
*ptr = 'A';
}
// This __except statement swallows
// Don't do this in your code
__except( EXCEPTION_EXECUTE_HANDLER
{
printf( "Caught an exception!\n"
return;
}

that prevents
whole block away

all exceptions
)
);

// This statement is needed for the ptr variable


// not to get optimized out
printf( "%s\n", ptr );
}
int main(int argc, char* argv[])
{
// See just how far the user would like to
// overwrite the buffer...
int elements = atoi( argv[1] );
// Create a heap buffer to put the shell code into
pHeapShell = (char*)malloc( sizeof( scode ) );
if( pHeapShell != NULL )
{
// Copy the shell code into our buffer
memcpy( pHeapShell, scode, sizeof( scode ) );
}
foo( elements );
printf( "Address of shell code is %p\n", scode );
if( pHeapShell != NULL )
free( pHeapShell );
return 0;
}

This program makes no attempt to pretend to be an actual application someone might write
intentionally, but which happens to make a few mistakes. Some of the errors shown here are
unfortunately all too commonthe most egregious example is that were taking user-supplied
data and using it as a count. If we compile this application using Visual Studio .NET, using
default settings and /GS enabled, we get several different behaviors. With a small count, the
output will look like this:
c:\ projects> SafeSehTest.exe 1
A
Address of shell code is 00408040

Chapter 3

Buffer Overrun Defenses

71

Now lets say we raise the count to be large enough to trip the exception handler within the
try-except block:
c:\ projects>SafeSehTest.exe 32
!"#$%&'()*+,-./0123456789:;<=>?
Caught an exception!

This will be followed shortly by Windows Vista telling us that the application has a buffer
overrun and cannot safely continue. So far, we havent given the application enough elements
to overwrite the exception handler; lets try a larger number:
c:\ projects>SafeSehTest.exe 92
!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMN

Were now looking at an extra instance of calc.exe running on the desktop. The shell code
nicely called exit on the process once it ran. Note that we used EXITFUNC = process, not
EXITFUNC = seh as in the previous example because if we continue to throw exceptions into
a process with a corrupted exception handler, well just keep recursively calling the shell code
until the process overflows the stackit runs out of room for the stack, not an overwrite condition. This will result in about 100 instances of calc.exe runningor attempting to run and
failingon the desktop. If we keep increasing the size of the overwrite, the application will
cause an exception before it hits our contrived exception; it doesnt print anything, but we do
have calc.exe running.
To test how the changes in Visual Studio 2005 help protect things in this case, lets modify the
code a bit. First, get rid of the straightforward stack overwrite by commenting out the first line
inside the for loop, and change the problem to a far more serious case where an arbitrary
DWORD is written to the address of our choice. With this sort of attack, well find that /GS
wont help us because the cookie isnt tampered with. With the compiler used for this example, we find that the address of the exception handler pointer is located at buf + 0x38, not buf
+ 0x30, like it was in the version compiled with Visual Studio .NET. Note that we have two
mitigations on by default: /GS and SafeSEH. We can also enable NX. If we enable only
SafeSEH, were told that SafeSehTest.exe has stopped working. This is to be expected because
the shell code isnt a registered exception handler.
Now, restore the overwrite by enabling the first statement in the for loop, re-enable /GS, and
disable SafeSEH. Now the app crashes, just as it did with only SafeSEH enabled. This is interesting, because /GS on the older compiler was unable to save us from this attack. The change
were seeing is that if /GS is enabled, and we try to jump to an exception handler, the stack
cookie is checked, and the clever attack noted by Mr. Litchfield is foiled.
For a third approach, disable SafeSEH and /GS, then enable NX. If we try the code in this case,
we find that the attack is foiled again. Its interesting how three different sets of protections
will each individually stop the original attack. Even with the far more dangerous arbitrary
4-byte overwrite, two of the three protections will take effect to prevent an attack against the
exception handler. Please note that were not claiming arbitrary 4-byte overwrites are no

72

Writing Secure Code for Windows Vista

longer dangerousjust those that are only able to overwrite one exception handler pointer.
Even with all these countermeasures in place, an arbitrary 4-byte overrun is considered very
dangerous and presumed exploitable.
If compiling 64-bit code, the exception records are compiled into the binary and arent kept
on the stack, which makes 64-bit executables much saferat least from SEH attacks.

Summary
Weve covered ASLR, stack and heap randomization, heap defenses, NX, /GS, and SafeSEH.
Unless there are compelling reasons, you need to be using all of these in your application.
Heres what you should be doing:

ASLR

Heap defenses

NX

Link with /NXCOMPAT

/GS

Dont do anything! Just take the defaults!

SafeSEH

Use the latest compiler

Link with the /dynamicbase option


Enable HeapTerminateOnCorrupt

Link with /SAFESEH

At the very least, Visual Studio 2005 with Service Pack 1and
ensure all of the DLLs the process links with are also compiled with the same compiler
and C runtime library.

So, whats still exploitable with all these overlapping countermeasures in place? Note that there
are ways to overcome every one of these mitigations. Overcoming them all at once is a lot
harder, but it is still possible. Data-driven attacks should also be considered. As a quick example, say an application would call LoadLibrary on a DLL, and an attacker was able to overwrite
the DLL path or nameyoud load the wrong DLL, and call the attackers DllMain function.
Some of the most prevalent attacks against Web servers dont involve arbitrary code but attack
the logic of the underlying application, and these attacks wont be thwarted by compiler or
linker options. At the end of the day, the only way to get secure code is to write solid code.

Call to Action

You should link your code with /dynamicbase, run a full test run, and ship with this
option enabled

You should link your applications with the /NXCOMPAT switch

References
Howard, Michael, and David LeBlanc. Writing Secure Code, 2nd
Edition. Redmond, WA: Microsoft Press, 2003.

(Howard and LeBlanc 2003)

Chapter 3

Buffer Overrun Defenses

73

(Humphrey 1999) Bugs or Defects? http://www.sei.cmu.edu/news-at-sei/columns/

watts_new/1999/March/watts-mar99.htm.
(LeBlanc 2004) LeBlanc, David. Integer Handling with the C++ SafeInt Class, http://

msdn.microsoft.com/library/ en-us/dncode/html/secure01142004.asp. January 2004.


(LeBlanc 2005) LeBlanc, David. Another Look at the SafeInt Class,

http://msdn2.microsoft.com/en-us/library/ms972819.aspx. May 2005.


(eEye 2001) eEye Digital Security. Microsoft Internet Information Services Remote Buffer

Overflow, http://research.eeye.com/html/advisories/published/AD20010618.html. June


2001.
Bypassing Windows Hardware-enforced Data Execution Prevention, http://www.uninformed.org/?v=2&a=4&t=txt. October 2005.

(Skape and Skywing 2005)

(Litchfield 2003) Litchfield, David. Defeating the Stack Based Buffer Overflow Prevention

Mechanism of Microsoft Windows 2003 Server, http://www.ngssoftware.com/papers/


defeating-w2k3-stack-protection.pdf. September 2003.

Chapter 4

Networking Defenses
In this chapter:
IPv6 Overview. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .76
Network List Manager. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .81
The Windows Vista RSS Platform . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .82
Winsock Secure Socket Extensions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .83
Windows Firewall with Advanced Security . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .85
Call to Action . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .95
References. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .95
Windows Vista has so many improvements and new features in the networking area, wed
really need a whole book to properly cover the topic in any real depth. While there are
improvements in nearly every area, and because any time you say network the phrase security implications naturally follows, were going to focus on the areas most likely to have a
strong security impact on ordinary applications. The following areas include a great deal of
new functionality:

Background Intelligent Transfer Service (BITS)This includes peer-to-peer functionality,


the ability to use IPv6 and HTTPS, and many other features.

Network List ManagerThis is a new interface available only on Windows Vista that
allows you to determine programmatically what type of network youre connected to.
Well be discussing this interface later in the chapter.

Peer-to-PeerAlthough peer-to-peer functionality has been available in Windows since


Windows XP SP1, Windows Vista introduces the peer-to-peer collaboration API. Some of
the key scenarios enabled by the collaboration API set are multiplayer games, conferencing, and many other growing areas. Peer-to-peer requires a lot of infrastructure and
builds from the ground up, and some of the implementations weve seen havent had
any real focus on security. If you build on the infrastructure provided here, youll have
more time to build a great application and spend less time worrying about the security
of the infrastructure. Unfortunately, peer-to-peer is too broad an area for us to cover here.

Network Diagnostics FrameworkThere isnt much connection between this framework


and security, but we thought it was cool enough to mention. If your application depends
heavily on the network being operational, this new set of APIs can help you figure out
whats wrong with your users connectivity to your server, which in turn allows you to
present the user with better and more actionable information.
75

76

Writing Secure Code for Windows Vista

IPv6Its here, its on by default, and you ought to start supporting it in your networked
applications. IPv6 still has a way to go before youll see many purely IPv6 networks,
mostly because of older operating systems and some infrastructure issues, but youll
need it to do peer-to-peer. Go learn more about it, and get ready to use it!

IP Helper APIThe IP helper APIs have been updated to give a lot more support for IPv6,
and theres too many helpful new functions to list here. If you do a lot of low-level sockets programming, check these out.

Windows RSS (Really Simple Syndication) PlatformWell cover this later in this chapter.

Windows SocketsThere are a lot of changes here, primarily around IPv6 support.
Theres also a really nice new API that allows you to connect to a remote server using a
list of addresses. Another major change is that support has been dropped for obsolete
protocols; only IPv4 and IPv6 are supported.

Windows Filtering PlatformIf you build firewall applications for use on Windows, you
need to check out the Windows SDK. If you just want your application to work well with
the Windows Advanced Firewall, read onwell cover that in detail. Hidden away in the
WFP documentation are some great new extensions to Winsock that allow you to
enforce security in your application and make it easy to impersonate socket clients.

Windows Firewall with Advanced SecurityWindows is getting a much more robust and
versatile firewall. The version available in Windows Vista can block outbound connections as well as inbound connections, can be applied to services, supports IPv6, and
much more. For a great user experience, youll want your application to register firewall
rules on set up.

TeredoThis is a transitional technology to allow IPv6 applications to work while transiting IPv4 networks, especially NAT (network address translation) devices. Teredo is
needed to enable peer-to-peer networking when running over the Internet.

IPv6 Overview
Although IPv6 isnt technically a security technology, this new network transport plays a
critical role in many new technologies that do have security implications. Depending on the
type of application youre writing, IPv6 support might be critical; for example, you might
choose to implement a game or a collaboration application using the peer-to-peer networking
facilities. Even if youre not creating applications that require IPv6 immediately, its always a
good thing to keep current.
An obvious reason to create IPv6 is that the original IP (Internet Protocol), known as IPv4
only uses 32 bits for network addresses. Once we subtract out the ranges used for multicast
and private address spaces (10.0.0.0/8 and 192.168.0.0/16 are two examples) and then
account for wasted address space, were clearly going to run out of address space relatively
soon. Using NATs helps stave off the inevitable, at the cost of end-to-end connectivity.

Chapter 4

Networking Defenses

77

As I write this, my home network is behind two NAT devicesa real proxy firewall and a cheap
router that accommodates the fact that my ISP regularly changes my address with DHCPand
the ISP has a NAT of its own. To make matters worse, this configuration would be difficult for
anyone who didnt have experience as a professional system administrator. As we move
forward, we can foresee needing several network addresses per person and per household,
and all of this needs to be easily configured. IPv6 solves most of these problems by design.
One of the most significant changes between IPv4 and IPv6 is that instead of the host portion
of an address using a variable number of bits, IPv6 is evenly divided between a 64-bit network
address and a 64-bit host portion. This allows for more devices than were likely to use on this
planet; it works out to several billion available addresses per person. An IPv6 address looks
like this:
fe80::e93a:50e5:6301:aa03

Note that the :: means some number of sequential zeros. Everything after that sequence is
the host portion of this systems address, and the network portion of the address is
fe80:0000:0000:0000, which happens to be the reserved network identifier for link local
addresses.
On a typical IPv6 system, there might be a number of assigned addresses; the first would be
the link local address, which is only good for the local network segment. When writing applications for IPv4, it can take a good bit of tricky code to restrict your application to just the local
network, although the new Windows Vista firewall APIs can help as well see later in this
chapter. When youre writing for IPv6, its trivial to just bind your application to the local
address, and you wont need to worry about traffic from outside the network. The second IPv6
address that could be encountered is the site address; it would be used for communications
within your enterprise network, but it wont be passed along by external routers. Finally, if
you have a connection to the global IPv6 network, youd also have a global IPv6 address thats
fully routable. As you can see, we now have several tools available to determine just what the
service scope of our applications should be. A fourth type of address you will find on a default
installation of Windows Vista is the Teredo Tunnel Adapter address; well cover this in more
detail shortly.
IPv6 also has a some great features; for example, IPSec is built into the IPv6 requirements;
extensibility allows for multiple, arbitrary sized headers; and best yet, autoconfiguration is
standard. The current state of running a home network is similar to the bad old days of configuring the interrupts needed by your hardware; eventually, IPv6 will resemble dealing with
USB devicesyou plug in the network cable and it just works.
If this short overview has sparked your interest, heres some references that can come in
handy:

IPv6 From Wikipedia, the free encyclopedia, http://en.wikipedia.org/wiki/Ipv6.

IPv6: The New Internet Protocol, 2nd edition, by Christian Huitema (Prentice Hall 1998).

78

Writing Secure Code for Windows Vista

Understanding IPv6 by Joseph Davies (Microsoft Press 2002).

Internetworking with TCP/IP Vol.1: Principles, Protocols and Architecture, 4th edition, by
Douglas E. Comer (Prentice Hall 2000).

There are currently many books on this topic, and were not asserting these are the best references, just those that weve found helpful. Wikipedia has the advantage of staying current,
and it has a number of helpful links.

Teredo
Teredo has a somewhat colorful history. Originally, Teredo was known as Shipworm, and the
name was created with the idea of enabling applications to transit networks behind NAT
devices, but it also gave an entirely different image to people charged with maintaining operational security. Having worms eating holes in the firewalls you put there to protect your network is worthy of horror movies! Possibly due to the connotations of the name Shipworm,
the protocol was renamed to Teredo, which is really the same thingthe most common type of
shipworm has a Latin name of Teredo navalis! Despite the colorful name, Teredo has evolved
into one of the more secure and firewall-friendly ways for applications to transit across NAT
devices and firewalls.
There are two fundamental problems Teredo is designed to solve. First, there are too many
systems behind devices that only support IPv4. We need a way to be able to get IPv6 to a
useful state without everyone running out and replacing their home router/firewall devices,
not to mention all the Internet service providers updating their networks. Second, most
people are behind at least one NAT device, often two. For applications that need end-to-end
connectivity (such as peer-to-peer networking, games, and collaboration scenarios), NAT
devices are preventing effective solutions from being created.
Teredo works by encapsulating IPv6 on top of IPv4 UDP packets. Although there are other
approaches that can be used when we can assume clear end-to-end connectivity, such as on a
large enterprise network, Teredo is assuming that NAT devices need to be traversed.
The first thing a client needs to do is send an initial packet to a properly configured Teredo
server. The Teredo server is responsible for being able to refer clients to a Teredo relay, and it
doesnt do much else: the goal is for a Teredo server to consume very little network bandwidth. The initial packet consists of an IPv6 ping with a large random number as the payload
carried on top of a UDP packet sent to port 3544. The IPv6 portion of the initial packet is then
forwarded to the IPv6 address the client is trying to reach, which would then send the reply
to the nearest Teredo relay. Thus, the relay can be thought of as a somewhat specialized
router.
The relay now needs to be able to put the response back into an IPv4 UDP packet and send it
back to the client. It does this by cleverly using portions of the IPv6 address to encapsulate the
information needed.

Chapter 4

Networking Defenses

IPv

6p

ing

resp

79

ons

ing

6p

IPv6 Server

IPv

Teredo Relay
e

ns

po

Teredo Server

Ter
e

do

ng

Re

6
Pv

qu

est

qu

e
oR

Figure 4-1

pi

est

e
Ter

s
re

Home Router

Diagram of Teredo initialization.

The first 32 bits of the Teredo IPv6 address is the Teredo prefix: 2001:0000. The next 32 bits
contain the IPv4 address of the primary Teredo server that sent the packet, which is followed
by 16 bits of flags and some information used to inhibit random scanning attacks. Finally, the
actual IPv4 address and the port used by the NAT is obfuscated within the final 48 bits. We
now see that the relay has all the information needed to reconstruct the UDP reply packet and
send it to the client.
You may be wondering how UDP packets sent to one host will get back to you if another host
replies. The answer is that you have 4 different types of NAT devices in general use:

Full coneA full-cone NAT establishes an external UDP port when sending an outbound packet and will forward traffic sent to that port from any IP address and any port
back to the originating port on the internal system. This doesnt sound very secure, and

80

Writing Secure Code for Windows Vista

it isntthis feature is why you should never depend on an NAT for security. It does
conserve resources on the NAT device, which is the primary design goal of this type of
system.

Restricted coneThis type of NAT maintains some level of state and requires that replies
come from the same IP address as the initial request was sent to.

Port-restricted coneReplies must come from the same IP address and port as the
request.

SymmetricIn addition to the requirements for a port-restricted cone NAT, the symmetric NAT will create a new mapping of internal IP address and port to external IP address
and port for traffic sent to every individual external host. This type of NAT is somewhat
more secure and is typically only seen in fairly expensive higher-end firewalls.

Some newer NAT devices can also appear to be port restricted under some conditions and
symmetric under others:
In particular, we found out that many NAT have a 5th strategy, port conservation.
Basically, they will try to keep the same port number inside and outside, unless it is already
used for another connection, in which case they pick a different one either sequentially (from
a global variable) or randombly. These NATs appear typically port restricted during the
tests, but behave as symmetric under load. (Huitema, personal communication)
If youre interested in the details, consult RFC 3489 (Rosenberg et al. 2003).
Back to our Teredo relay! It will send the reply back to the Teredo client. If the reply reaches
the client, the client then knows it is behind a cone NAT. There are a number of scenarios that
can come into play, but the primary thing is that the Teredo relay will attempt to get out of the
relay business entirely and just let the clients exchange packets directly, which can be done
when two IPv6 systems are behind different Teredo-compatable NAT devices.
What all of this means to you is that it is now possible to create applications that can deal
directly with one another, even if they are behind NAT devices. You get end-to-end connectivity, and, as IPv6 becomes ubiquitous, it will continue to work, just better.
There are some security implications of Teredo. If youre operating a firewall, the protocol is
designed to be completely transparent. If you dont want to allow Teredo, just block one UDP
port; if you wanted to selectively manage Teredo traffic, all the information you need is available
so that it should be easy to write a Teredo-specific packet handlerand it would be very efficient.
Out of all the tunneling approaches currently in use, this one is one of the easiest for the network administrators to deal withwhich is smart because happy and secure network admins
are less likely to just block your traffic. On the client side, a socket has to specifically request that
it would like to accept Teredo traffic on Windows XP, and on Windows Vista, Teredo traffic is
controlled by the firewall settings, so the only applications on your system exposed by Teredo
would be those that expect to deal directly with the Internet. In later sections, well show you
how to create host-based firewall rules that explicitly allow or deny Teredo.

Chapter 4

Networking Defenses

81

Network List Manager


As programmers, weve never had an easy time trying to figure out whether the computer was
connected to a network and what sort of network it was connected to; in some extreme cases
in the really bad old days, we were reduced to redirecting the output of console applications
and parsing the text! Over the years, things have gotten better: Windows XP and Windows
Server 2003 gave us the Network Location Awareness Winsock extensions. The IP helper API
set, found in Windows 2000 and later, was a huge step in the right direction as well.
With Windows Vista, we now have the Network List Manager (NLM) APIs, that bring most of
what we need into a common set of functions.
You may also be wondering why were covering the NLM in a book about security. You might
rightly accuse us of being network programming geeks, but networks and security go hand-inhand. If you dont understand what the network is doing, you cant hope to effectively secure
an application that interacts with the network, and there isnt much these days that doesnt
deal with the network directly or indirectly. Some of the concepts and properties of networks
discovered through the NLM will play an important role later in this chapter when we discuss
the new firewalling API sets.
Were not going to attempt to cover the material presented in the Windows SDK here; this is
just a quick overview so youll know whats available. The highest level interface you might
want to deal with is the INetworkListManager, which allows you to determine whether:

The system is connected to any network, via the get_IsConnected property.

The system is connected to the Internet, using the get_IsConnectedToInternet property.

The system as a whole has connectivity to a local subnet, a local network, or the Internet.
All of these parameters can be found for both IPv4 and IPv6. This information is
obtained using the GetConnectivity method.

An enumerator for the list of network connections on this system can be obtained. You
can find only connected, only disconnected, or all networks using the GetNetworks
method. You can also find all the connections using the GetNetworkConnections method.

A related interface is the INetworkListManagerEvents, which exposes one sink method, ConnectivityChanged. The ConnectivityChanged method allows your application to be notified if any of
the properties INetworkListManager::GetConnectivity returns have changed. At a more granular
level, you can also register sinks exposed by the INetworkEvents interface to determine if a
network has been added or dropped. Unless youre writing a network monitoring or management tool, its rare for an application to need to drop to this level.
Although most of the properties for individual networks arent especially interesting from a security perspective, the INetwork::GetDomainType method tell us whether a domain controller is
present on your network and, if one is present, whether your connection has authenticated to the
domain controller. Some applications should change functionality when domain status changes.

82

Writing Secure Code for Windows Vista

For example, Outlook 2007 knows to connect to the internal Exchange server when my laptop is
connected to the Microsoft corporate network, but it isnt confused by my home domain controller when connected to my home network and instead connects to Outlook Web Access.
Another interesting property of a network is obtained from INetwork::GetCategory, and this tells
you if youre on a domain, public, or private network. The firewall included with Windows Vista
determines which policy to use on the basis of the return value for this method. If your application changes firewall rules depending on which network category your customers system is
connected toand please note that this is a property of a network, which means that you could
have different rules in effect for different networksthen you may want to monitor the system for
changes so that your application can gracefully handle changes instead of presenting unintelligible errors to the user. Additionally, you may want your application to behave more conservatively and expose less attack surface when running on a public network.

The Windows Vista RSS Platform


There has been a great deal of talk, speculation, and real-world vulnerabilities (CVE-20064660) and (CVE-2006-4712) attributed to Real Simple Syndication (RSS) feeds. At Microsoft
we envisaged such an attack vector and have spent a great deal of time adding defenses to the
RSS platform in the operating system, and it is highly recommended that you use the built-in
RSS infrastructure rather than performing the data parsing yourself if you want to build an
application that uses RSS. Were not saying the RSS platform is impervious to attacks, but we
have spent countless hours hardening it against assault. For example, the platform sanitizes
feed content (Microsoft 2006a) and strips out script prior to storing the content. The code
that does this sanitization was developed in Office and is derived from the code used to successfully sanitize billions of Hotmail email messages.
Important

Of course, we cant expect you to rewrite your product to use the RSS platform
in Windows Vista, but if you are building a product that includes RSS support, then you
should seriously consider using the RSS platform in Windows Vista.

The Windows RSS platform offers two COM interfaces: a vtable version for C/C++ developers
starting with the IXFeedsManager interface, and a late-bound IDispatch-derived interface
named IFeedsManager. You must include <msfeeds.h> in your code to access these interface
definitions.
A full treatise of the Windows RSS platform is beyond the scope of this book, and you can find
more information about it at MSDN (Microsoft 2006b), but to give you a feel for how to use
the RSS infrastructure, the following code will enumerate all feeds in the root folder, and
display each feeds name, URL, and item count.
HRESULT hr = CoInitialize (NULL);
if (FAILED(hr))
return hr;

Chapter 4

Networking Defenses

83

CComPtr<IXFeedsManager> spIXFeedsManager;
hr = spIXFeedsManager.CoCreateInstance(CLSID_XFeedsManager, NULL, CLSCTX_INPROC_SERVER);
if (FAILED(hr))
return hr;
CComPtr<IXFeedFolder> spIXRoot;
hr = spIXFeedsManager->RootFolder(IID_PPV_ARGS(&spIXRoot));
if(SUCCEEDED(hr)) {
CComPtr<IXFeedsEnum> spIXFeedsEnum;
hr = spIXRoot->Feeds(&spIXFeedsEnum);
if (SUCCEEDED(hr)) {
UINT uiFeedCount = 0;
hr = spIXFeedsEnum->Count(&uiFeedCount);
while (uiFeedCount && (SUCCEEDED(hr))) {
CComPtr<IXFeed> spIXFeed;
hr = spIXFeedsEnum->Item(--uiFeedCount, IID_PPV_ARGS(&spIXFeed));
if (SUCCEEDED(hr)) {
LPWSTR wszName = NULL;
if (SUCCEEDED(spIXFeed->Name(&wszName))) {
wprintf(L"%s",wszName);
CoTaskMemFree(wszName);
}
LPWSTR wszUrl = NULL;
if (SUCCEEDED(spIXFeed->Url(&wszUrl))) {
wprintf(L" from %s",wszUrl);
CoTaskMemFree(wszUrl);
}
UINT cItems;
if (SUCCEEDED(spIXFeed->ItemCount(&cItems))) {
wprintf(L" has %d items.\n",cItems);
}
spIXFeed = NULL;
}
spIXFeedsEnum = NULL;
if (uiFeedCount)
hr = spIXRoot->Feeds(&spIXFeedsEnum);
}
}
}
spIXRoot = NULL;
spIXFeedsManager = NULL;
CoUninitialize();

Winsock Secure Socket Extensions


In the second edition of Writing Secure Code, we said we hoped one day wed be able to require
IPSec on a socket at run time from an application, instead of hoping that the administrator
had read the manual and actually configured the application at the network level. It seems
that the networking team was listening, because exactly this functionality ended up shipping
in Windows Vista. The Windows Platform SDK topic to look up is Windows Filtering Platform API Secure Socket Functions. Were only going to give you a quick overview of these
functions here. The first function is WSASetSocketSecurity. Your code should call

84

Writing Secure Code for Windows Vista

WSASetSocketSecurity before either calling bind (assuming youre writing a server) or connect
(assuming youre creating a client), and if youre writing a kernel mode application, youll
need to use WSAIoctl to set the security settings. To use this API, youll need to set up a
SOCKET_SECURITY_SETTINGS structure, which is defined here:
typedef struct _SOCKET_SECURITY_SETTINGS
{
SOCKET_SECURITY_PROTOCOL securityProtocol;
ULONG securityFlags;
} SOCKET_SECURITY_SETTINGS;

The securityProtocol member has two valid values currently defined: SOCKET_SECURITY_
PROTOCOL_DEFAULT, which is what youd get using a default socket, and SOCKET_
SECURITY_PROTOCOL_IPSEC, which actually enforces that IPSec be used for this socket.
Unfortunately, it isnt quite that simple. Once you set the SecurityProtocol member to
SOCKET_SECURITY_PROTOCOL_IPSEC, WSASetSocketSecurity expects to be passed a
SOCKET_SECURITY_SETTINGS_IPSEC structure. The first option you can use determines
whether IPSec is required to allow connections, or well just use IPSec when available, which is
done by setting the SecurityFlags member to either SOCKET_SETTINGS_GUARANTEE_
ENCRYPTION or SOCKET_SETTINGS_ALLOW_INSECURE. If you choose to allow insecure
connections, you may want to call WSAQuerySocketSecurity on connections and branch your
code depending on whether the connection is secure or not. There is one flag in the
IpsecFlags member definedSOCKET_SETTINGS_IPSEC_SKIP_FILTER_INSTANTIATION
which is used when you know that the IPSec policy has already been configured for your application. Note that if you supply NULL as the pointer to the SOCKET_SECURITY_SETTINGS
structure, default IPSec configuration for that system will be applied to your application.
Although weve been able to do server authentication and impersonation of socket clients in
the past, it involved writing quite a lot of fairly messy Security Support Provider Interface
(SSPI) code. Among the improvements in Windows Vista is WSASetSocketPeerTargetName,
which allows the client to specify the service principal name (SPN) of the server and application (Microsoft 2007) they want to connect to. If this option is used, once connect returns success, we know weve connected to the server we intended to connect to. Its important to know
what server youre connecting to, because the next interesting API is WSAImpersonateSocketPeer, which is what the server is going to call to identify the user thats just connected and to
make access control decisions. If youre writing a server application, be sure to check whether
the impersonation succeeded, and remember to call WSARevertImpersonation as soon as
youre done checking access. You should also remember to carefully take into account exceptions (whether C++ or SEH exceptions) thrown while inside a block thats impersonating. If
youre able to leverage C++, a good approach is to create a class that reverts the impersonation
in the destructorthen youre guaranteed to revert as the stack unwinds. If youre using C, or
cant use C++ exception handlers, try-finally can achieve the same effect.
Overall, this is a great set of useful new API calls. The alternative is to write a lot of messy code,
and weve seen ISVs go as far as using embedded Web servers with SSL/TLS to accomplish

Chapter 4

Networking Defenses

85

the same thingtoo bad they also forgot to set up certificates correctly for the SSL/TLS connection and accomplished little more than security by obscurity. Once the platform support
for the new socket options is widespread, these new socket options will make getting real
security a lot easier.

Windows Firewall with Advanced Security


The new firewall available with Windows Vista has more features than the previous version,
and it is relatively easy to write code to configure the firewall properly for your application.
Our sample code shows you how to check the current firewall settings, get and examine the
current rules, create rules, and manipulate groups of rules. As with some of our other samples, we have yet more lessons from the School of Hard Knocks that will hopefully save you
some time. Lets dive in and take a look at whats available and how to use it.

Global Firewall Settings


The first piece of code well need retrieves a NetFwPolicy2 object, defined in NetFw.h, which in
turn allows us to retrieve global settings, manipulate groups of rules, and obtain an interface
to the rules. If you were thinking of getting the NetFwPolicy2 object from the NetFwMgr, like
you would have for the older NetFwPolicy interfaces, think again: you just instantiate an
instance with CoCreateInstance:
hr = CoCreateInstance( __uuidof(NetFwPolicy2),
NULL,
CLSCTX_INPROC_SERVER,
IID_INetFwPolicy2,
(void**)&pFwPolicy2 );

A helpful hint is to search for CLSID in the NetFw.h header; this shows you the COM classes
you can instantiate directly with CoCreateInstance, as opposed to having to acquire an interface
pointer through a class method. The currently defined classes are:
NetFwRule (Advanced Firewall)
NetFwOpenPort
NetFwAuthorizedApplication
NetFwPolicy2 (Advanced Firewall)
NetFwMgr

Now that you have an instance of the NetFwPolicy2 object, we can get information about the
current status of the firewall, and which policy is in effect with the following:
long CurrentProfileType;
printf( "Checking current profile type:\n" );
hr = pFwPolicy2->get_CurrentProfileTypes( &CurrentProfileType );
if( SUCCEEDED( hr ) )
{
// The profile type can currently be treated as exclusive,
// but this may not be true in the future, so check it like this:

86

Writing Secure Code for Windows Vista


if( CurrentProfileType & NET_FW_PROFILE2_DOMAIN )
printf( "Current profile type is domain\n" );
if( CurrentProfileType & NET_FW_PROFILE2_PRIVATE )
printf( "Current profile type is private\n" );
if( CurrentProfileType & NET_FW_PROFILE2_PRIVATE )
printf( "Current profile type is public\n" );
}

If the system is joined to a domain and is able to locate a domain controller for its forest, the
domain policy will take effectwhich could be pushed down from the domain controller. If
the system is exposed to a public network, the public policy would be used, and if youre running on a private network, the private policy would take effect. When you write rules for your
application, which policy to enable is a primary consideration; for example, we might not
want something like Universal Plug and Play (UPnP) running on a corporate networkits
unlikely to be a great idea on a public network, but its probably very useful on a private network. Think through your choices about which profiles to support with your rules in terms of
principle of least privilege. If you use our GetFirewallSettings sample to dump all of the rules on
your Windows Vista system, youll see some applications that have different rules for each
profile and some that only support some of the profiles. You can also check whether modifications can succeed with this code:
printf( "Checking whether modifications will succeed:\n" );
NET_FW_MODIFY_STATE ModifyState;
hr = pFwPolicy2->get_LocalPolicyModifyState( &ModifyState );
if( SUCCEEDED( hr ) )
{
switch( CurrentProfileType )
{
case NET_FW_MODIFY_STATE_OK:
printf( "Modifications are OK\n" );
break;
case NET_FW_MODIFY_STATE_GP_OVERRIDE:
printf( "Firewall state set by group policy\n" );
break;
case NET_FW_MODIFY_STATE_INBOUND_BLOCKED:
// This means your rule will be applied, but
// wont work because of blocked inbound connections.
printf( "Inbound connections are blocked\n" );
break;
}
}

For each policy level, the following properties are configurable on an individual basis:

BlockAllInboundTraffic

DefaultInboundActionThe shipping default is to block, and wed strongly recommend


not tampering with this setting.

DefaultOutboundActionThe default here is to allow connections to external systems.

ExcludedInterfacesLists any network interfaces excluded from this policy level.

Chapter 4

Networking Defenses

87

FirewallEnabled

NotificationsDisabledDisables desktop notification, which would typically be used in a


controlled enterprise scenario.

UnicastResponsesToMulticastBroadcastDisabledAllows or disallows responses directly to


the sender of a multicast broadcast packet.

In general, applications should not modify systemwide settings, but it can often be useful to
determine whether a setting might be in place that would cause your application to either
malfunction or have reduced functionality and then notify the user. If it is important to the
security of your application for the firewall rules to be in effect, you may want to warn the user
if the firewall is disabled. Note that applications need to be fully elevated to administrator to
change firewall settings.

Creating Rules
There are two main tasks to creating good firewall rules. The first is understanding how to use
the APIs to create rules and put them into groups. Due to some documentation errors, this
isnt as easy as it looks, but weve sorted out these issues so you can avoid them. In all likelihood, unless you are one of the first ones to buy this book, the documentation errors will have
already been fixed, and a couple of functional issues are scheduled to be fixed in Windows
Vista service pack 1.
The second part of creating good firewall rules is much harderknowing both how your application needs to work with the network and knowing the types of attacks that someone might
launch against your application. First, well show you what can be done with the Advanced
Windows Firewall, and then well show you the rules we wrote for our sample application and
why each of these rules is important. One note, although the Advanced Windows Firewall is
indeed very advanced compared to the previous Windows Firewall shipping in Windows XP,
it isnt going to allow you to do some of the things you could do with a fully featured,
enterprise-class firewall. For the most part, these limitations arent a significant problem, but
if they are, you can do nearly anything you like by writing filters for the Windows Filtering
Platform, which is also documented in the Windows SDK. To be completely fair, its also true
that the Advanced Windows Firewall allows you to create rules that might be difficult using
other approaches, such as applying rules only to wireless interfaces.
Using the Advanced Windows Firewall rules, a firewall rule can have the following
properties:

ApplicationNameThis property takes a full path to the binary youre running. Wed
suggest copying the executables into a staging directory or creating two sets of rules, one
for debug and another for release.

DescriptionThe description is just a user aid and documents what youre trying to
accomplish with this rule.

88

Writing Secure Code for Windows Vista

DirectionThis is the direction traffic will flow, and is one of two enum values: NET_FW_
RULE_DIR_IN or NET_FW_RULE_DIR_OUT. Rules regulating what can go from your
application to other points on the network are outbound rules, and rules regulating
what can come from the network to your application are inbound rules. Note that some
protocols, such as TCP, are considered directional, and enterprise-class firewalls can
write rules that allow connections to be made in only one direction. This version of the
firewall rules doesnt support this level of functionality, although it isnt as important for
a host-based application-level firewall to be able to regulate the TCP connections at this
level.

EdgeTraversalThis setting determines whether the traffic is allowed to be sent across


the Teredo tunnel adapter. Unless you have an IPv6-enabled application and would like
it to work beyond your local network, you can leave this at the default, which is disabled.

EnabledVery simply, this determines whether the rule is turned on or off.

GroupingThe grouping property is important but tricky. If your rules have a grouping
property, you can manage them all at once, which well show you later in the chapter.
The documentation tends to expect that you can feed a simple BSTR into this property,
such as My Apps Rule Group, and it ought to work, but unfortunately, this wont work
until service pack 1. You can give it the path and string ID to a string stored in a resource
DLL, and well show you how this is done.

IcmpTypesAndCodesThe ICMP types and codes allows you to regulate what type of
ICMP traffic is allowed to be passed along to your application. The types and codes are
passed in as strings, so if your application sent pings (ICMP echo request) and expected
replies, your rule would need to allow 0:0,8:0where type 8 is an IPv4 echo request,
code 0 is the only documented code for that type, and type 0 is an echo reply type, again
with a corresponding code of 0. If your application needed to deal with all of the ICMP
unreachable packets, the way to write the rule is to specify 3:*which is interpreted as
type 3, all codes. If you use the sample code provided, you can dump the rules that come
with Windows Vista and see more examples. Hopefully, the details of how to actually
use this property will be documented in the Windows SDK soon.

InterfacesThis specifies which interfaces the rule applies to. The default is all interfaces. Well present a sample showing how to do this shortly.

InterfaceTypesThis is a string specifying the type of interface to apply the rules on.
Currently allowed values are RemoteAccess, Wireless, Lan, and All.

LocalAddressesThis specifies the local addresses a rule applies to. In most cases, youd
set this to *meaning all interfaces. You can specify a list of comma-separated IP
addresses (no spaces), a range of IP addresses (for example, 192.168.0.1-192.168.0.255),
or you can use CIDR notation (192.168.0.0/24 in CIDR means the same thing as the previous range example). The documentation states that you can use netmask notation,
which would specify the 192.168.0.x network as 192.168.0.0 mask 255.255.255.0, but
in reality, this isnt supported and wont work. Although it is annoying that the Windows

Chapter 4

Networking Defenses

89

SDK doesnt correspond to what works, it isnt a serious problem because CIDR notation
accomplishes exactly the same thing, is more compact, and is easier to understand.
Ranges could be used as well. Strings designating IPv6 addresses are also supported.

LocalPortsThe local ports tell us what ports are affected by the rule. You can specify
* for all ports, or you can specify an individual port. If you want to specify more than
one port, a comma-separated list will do it (such as 7, 8, 9). Unfortunately, ranges
arent available for ports in this version. Another issue is that while its tempting to
copy and paste the list of properties into your code and then set them one-by-one so
you wont forget anything, if you try to set the local or remote ports prior to setting the
protocol to either TCP or UDP (6 or 17), the set_LocalPorts method will fail with an
error of invalid parameter. Although we havent tried it, the same may be true of the
ICMP types and codes. Just remember to set the protocol first, and things will work as
expected. The following keywords are supported (Yariv and Mohan, personal
communication):

RPC: a special keyword designating a port used by the RPC run-time DLL. When
the RPC run-time DLL is using a dynamically assigned port to receive traffic for a
given interface (RPC/TCP), it marks the socket in a special way that is detected by
Windows Firewall. Specifying this keyword in the LocalPort attribute means the
port is dynamically assigned and used for RPC purposes.

RPC-EPMap: a special keyword used to designate the RPC end-point mapper port.
This is used by the RPCSS service when it uses TCP/135 for RPC/TCP end-point
mapping and TCP/593 for RPC/HTTP end-point mapping. Instead of specifying
this fixed port, by using this keyword the firewall is being notified by the RPCSS
service of the right port it needs and dynamically opens/closes these ports on the
fly as RPC interfaces are being registered/unregistered. This port keyword is used
in the Windows Firewall out-of-box policy and should also be used for third-party
cases where dynamic RPC is being used.

Teredo: a special keyword used to designate the dynamic ports the Teredo service
is using to perform its NAT-traversal magic. By using this keyword, the firewall is
being notified by the Teredo service of the right port(s) it needs and dynamically
opens/closes these ports on the fly as Teredo is being utilized. This port keyword
is used in the Windows Firewall out-of-box policy and should probably not be
used in third-party scenarios.

NameThis is simply the name of the rule, specified by a string.

ProfilesThe profiles property determines whether the rule applies to public, private, or
domain profiles. This same set of properties shows up in the NLM APIs discussed earlier
in this chapter.

ProtocolThis is the protocol for your traffic. Typically, this would be 1 for ICMP,
6 for TCP, or 17 for UDP. IPv6 is specified by 41. Out of the 255 possible values,
close to 140 are currently defined. You can find a complete and current list at

90

Writing Secure Code for Windows Vista

http://www.iana.org/assignments/protocol-numbers. If theres not an RFC listed along


with the protocol, its probably something used in the early days of IP networking and
hasnt been seen since.

RemoteAddressesThe remote addresses follow the same rules as the local addresses,
but theres also a predefined string that is very useful: LocalSubnet means that we only
want to accept local traffic.

RemotePortsLike the LocalPorts property, this specfies which remote ports your application can access. For most server applications, this would be any port (or *), and for
client applications, youd specify the port the server listens on.

ServiceNameThis specifies the name of the service the rule applies to. Many services
run under the same application name, and this setting is needed to distinguish between
the large number of services running under svchost.exe, to give the most common example. Once you understand how to create rules, well show you how to apply this setting
in Chapter 6, which covers services. If your service isnt a sockets application, the default
rule blocks everything, which is both easy and does exactly what you want.

Setting the Group and Interface Properties


Setting the group property string is essential to being able to turn on and off all your
rules in a group, and it ought to be as easy as doing this:
BSTR Group = SysAllocString( L"My Rule Group" );
hr = pFwRuleIn->put_Grouping( Group );

Unfortunately, it wont work that way prior to service pack 1. What you actually need to
do is this:
BSTR Group =
SysAllocString( L"@c:\\scratch\\RuleSetResource.dll,-101" );
hr = pFwRuleIn->put_Grouping( Group );

So just what is this DLL, and whats the -101 for? Just follow these steps, and it isnt all
that onerous. First, create a new project under your solution. Make it a Win32 project,
tell it you want a DLL, and just take all the defaults. None of the code is actually important. Next, right-click at the top of the new project, and tell it youd like to add a new
resource. It will ask you what type of resource; select String Table. Drill down into the
new string table, and add a string for your group name. Take note of the string IDthe
first will be 101, which explains the -101 after the DLL name. What this also gives you,
nearly for free, is an easy way to localize your applications firewall rules for different
languages. Finally, remember at setup time to place the DLL on the users system, and
make sure the application setting your firewall rules has the full path to your resource
DLL. If youd like to learn more about the string syntax, see the Windows SDK documentation for SHLoadIndirectString.

Chapter 4

Networking Defenses

91

You can set the interface property using this code:


variant_t vtInterfaceName("Local Area Connection"), vtInterface;
long index = 0;
SAFEARRAY *pSa = NULL;
pSa = SafeArrayCreateVector(VT_VARIANT, 0, 1);
if (!pSa)
_com_issue_error(E_OUTOFMEMORY);
else
{
hr = SafeArrayPutElement(pSa, &index, &vtInterfaceName);
if FAILED(hr)
_com_issue_error(hr);
vtInterface.vt = VT_ARRAY | VT_VARIANT;
vtInterface.parray = pSa;
}

Now that weve documented all the foibles of the NetFwRule object, using them is fairly simple. You call CoCreateInstance on as many NetFwRule objects as you need, set all the properties
where the default isnt good enough, get an interface to the rules collection, and add your
rule(s). The code looks like this:
hr = CoCreateInstance( __uuidof(NetFwRule),
NULL,
CLSCTX_INPROC_SERVER,
IID_INetFwRule,
(void**)&pFwRuleIn );
// Go set up all the rule properties
// Now let's get a pointer to the rules
INetFwRules* pFwRules;
hr = pFwPolicy2->get_Rules( &pFwRules );
// Handle errors
hr = pFwRules->Add( pFwRuleIn );
if(SUCCEEDED(hr))
printf( "Added inbound rule\n" );
else
printf( "Could not add inbound rule - err = %x\n", hr );

The last remaining task is really the hardest part: how to make a rule set for your application.
For our example server, we created a simple TCP-based echo server. Although you wont often
see echo servers these days, they used to be very common and were used to establish network
connectivity and a quick check of latency and available bandwidth. An echo server listens on
a well-known, designated port (7) and sends back any ASCII string it was sent by the client.
Lets look at what we need to do. For inbound connections, we have to allow traffic from any
remote port to our local port 7. If the feature were available, wed prefer to be able to say that
we wanted to accept connections from dynamic portsport numbers greater than 1023 (ports
below that are reserved ports, although on Windows any application can use them). Unfortunately, port ranges arent available, so well just have to take all ports. For a silly example like

92

Writing Secure Code for Windows Vista

echo that can be used to eat up all our expensive bandwidth, it would be best to set the
RemoteAddresses to LocalSubnet. Your choice of RemoteAddresses could be different, and
is one of the more important decisions to make about your application.
Now that we can get inbound connections, we need another rule to specify where the replies
can go. Our first outbound rule is to allow traffic from local port 7 to all remote ports on the
local subnet, which is a straightforward reversal of the inbound rule. The second outbound
rule illustrates a more subtle problemwe certainly dont want to allow a situation where our
echo server can be tricked into having an endless conversation with another echo server. To
prevent this, well add an outbound rule that disallows traffic from our port 7 to any remote
port 7. If youre well educated about networks, you might point out that spoofing a connection
isnt so easy with TCP, and this is mostly a problem with UDPand youd be right! However,
this is just an example, and the point is that just because you need to reply to legitimate
inbound connections, there might be some things you ought not reply to.
If youre the inquisitive type, you might also be wondering why wed go to all this trouble to
restrict traffic to port 7 on our server. After all, the server only listens on port 7, and any connections attempted to other ports will just get met with a reset, so why not just allow all ports
to all ports? The answer to this is that if an attacker did take over your application, one of the
things they might do is bind a command shell to a port you might not noticesay, 54321. Your
echo service obviously has no business accepting connections on port 54321, but if you
allowed traffic to all ports, this is exactly what could happen. If you restrict the traffic to
port 7, the attackers attempt to bind a command shell to port 54321 will end up failing the
first time they call accept, and not knowing just what it is that made things break, they may
just move along to a less resistant victim. Another common ploy would be to make an outbound connection to another port, but in this case, our outbound rule has restricted them to
starting from port 7. If the attacker knows what is stopping them, only then could they bind
their source port to port 7 and make the outbound connection. You could stop them from
rebinding to port 7 by setting SO_EXCLUSIVEADDR, but you could get into issues trying to
restart on failure. The bottom line here is that principle of least privilege is always a good
thing, and this goes double if youre dealing with networked applications.
If youre writing a client application, you would just apply the same rules in reverse. Allow
connections from any local port to the servers port, and traffic from the servers port back to
any local port. If youve read (and followed) our advice on how to make firewall-friendly applications in the second edition of Writing Secure Code, writing firewall rules for your application
should be easy. If you didnt follow our advice and find yourself writing more than a dozen
rules to cover a myriad of connections between a large number of ports on both ends, or if you
forgot that sockets do go both ways and used two when you needed one, it might be time to
refresh your knowledge of that topic and perhaps write your application to play more nicely
with firewalls.

Chapter 4

Networking Defenses

93

Working with Rule Groups


Once you have your rules created, the easiest way to manipulate them is to use the group
interfaces exposed from the NetFwPolicy2 object. Unlike the rules themselves, the rule group
interfaces will work with the plain group string, or the resource DLL reference. The following
are equivalent for the demo rules:
BSTR group = SysAllocString( L"SocketServer Example" );
BSTR group = SysAllocString( L"@c:\\scratch\\RuleSetResource.dll,-101" );

You have methods available to determine if the rule group is currently enabled and whether the
rule group is enabled for each of the three profiles (domain, public, and private), and you can
enable or disable your rule group for each or all of the three profiles with one call. Take a look
at the CheckFirewallRuleSet sample application to see how to use the APIs. As with the rules,
be mindful that a VARIANT_BOOL isnt a bool, nor is it a BOOL. For example, this works:
if( SUCCEEDED( pFwPolicy2->EnableRuleGroup( profileTypesBitmask,
group, VARIANT_TRUE ) ) )
{
printf( "Rule group now enabled\n" );
}

If you had passed true or TRUE to EnableRuleGroup, it would not have worked.

BOOL, bool, and VARIANT_BOOL


Whats in a Boolean? All of these are various integer types, and we might tend to treat
them as interchangeable. For example, I might write:
BOOL fFoo = true;

And expect it to work. The compiler may complain, and it will certainly complain if we try
to assign TRUE to a bool, but it will indeed work as we expect. Unfortunately, if we mix
and match bool, BOOL, and VARIANT_BOOL, it wont always work, and if you write:
VARIANT_BOOL fEnabled = true;

It will compile cleanly, and if you pass fEnabled to any of the set methods for the preceding rules, youll find that it wont work. Despite having done a lot of work with integer
manipulation and overflows, this caused me significant amounts of programmer astonishment! To save you time, trouble, and headaches, heres whats really going on:
Type

Integer Representation

BOOL

signed int

bool

unsigned char

VARIANT_BOOL

signed short

Value When True

Value When False

-1

94

Writing Secure Code for Windows Vista

When armed with this information, we quickly see that if( VARIANT_TRUE == true) is
false, since -1 != 1! While were on the topic of bools, you may often run into annoying
warnings when you do something like assign the results of a Windows API that returns
BOOL to your C++ bool. The right way to do this is:
bool fRet = !!OpenProcessToken( ... );

What happens here is that the first unary not (!) performs an operator cast to type bool,
and then the second unary not changes the result to what you expected. A less elegant
way to do the same thing is:
bool fRet = OpenProcessToken( ... ) ? true : false;

If youve been programming for Windows for a long time, you may recall back in the 16bit days when TRUE was a 16-bit integer and was defined as -1. Because
VARIANT_BOOL is descended from Visual Basic, it has kept its 16-bit heritage, and
unfortunately VARIANT_TRUE is -1.
What should you do about all this? First, be aware of these differences. If something asks
you for a VARIANT_BOOL, pass it either VARIANT_TRUE, or VARIANT_FALSE. If
youre writing code that deals with VARIANT_BOOL, and youd like to be robust in the
face of unsuspecting C++ programmers thinking that true might be 1, write your code
like this:
if( fEnabled != VARIANT_FALSE )

not like this:


if( fEnabled == VARIANT_TRUE )

or better yet,
if( fEnabled )

You can always count on false being 0, but you cannot count on anything else, although
it is a happy side effect that I can cast a bool to a BOOL and back again without ever
changing the value.
A documentation problem we uncovered is that IsRuleGroupCurrentlyEnabled is documented,
whereas get_IsRuleGroupCurrentlyEnabled is what actually exists in the header and will compile. Hopefully, by the time youre reading this, the documentation will have been updated
and will be correct.

Chapter 4

Networking Defenses

95

Call to Action

Learn about IPv6 and support it in your applications.

Use the NLM APIs to get information about network changes, and make your application handle changes gracefully.

Learn how to create correct firewall rules for your application and enable them.

References
(Huitema, personal communication)

Huitema, Christian, personal communication

February, 2007.
(RFC 3489) Internet Engineering Taskforce, Network Working Group (Rosenberg

et al.). STUNSimple Traversal of User Datagram Protocol (UDP) through Network


Address Translators (NATs), http://tools.ietf.org/html/rfc3489. March 2003.
Multiple Cross-Site Scripting (XSS) Vulnerabilities in the RSS Feed
Module in AOL ICQ Toolbar, http://nvd.nist.gov/nvd.cfm?cvename=CVE-2006-4660.

(CVE-2006-4660)

Multiple Cross-Site Scripting (XSS) Vulnerabilities in Sage 1.3.6, http://


nvd.nist.gov/nvd.cfm?cvename=CVE-2006-4712.

(CVE-2006-4712)

(Microsoft 2006a) Microsoft Windows Software Development Kit for Windows Vista and

.NET Framework 3.0 Runtime Components, http://www.microsoft.com/downloads/


details.aspx?FamilyId=C2B1E300-F358-4523-B479-F53D234CDCCF&displaylang=en.
The Windows RSS Platform, http://msdn.microsoft.com/library/
default.asp?url=/library/en-us/FeedsAPI/rss/rss_entry.asp.

(Microsoft 2006b)

(Microsoft 2007) Service Principal Names, http://msdn2.microsoft.com/en-us/library/

ms677949.aspx.
(Yariv and Mohan, personal communication) Yariv, Eran, and Mahesh Mohan, Microsoft

Windows Networking Group, personal communication February, 2007.

Chapter 5

Creating Secure and Resilient


Services
In this chapter:
Services Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .97
Service Accounts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .99
Reducing Privileges . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .102
Controlling Network Access. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .107
Communicating with the Desktop . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .110
Lessons from the School of Hard Knocks. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .117
Call to Action . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .118
References. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .119
There are many new features added to Windows Vista that allow you to make your services
more secure. In this chapter, well give you a guided tour of these features, as well as show you
how to create a service that communicates securely with the desktop. To demonstrate how
these features work, we wrote a fully featured service that will be used for examples throughout the chapter. Writing a service in C/C++ requires a surprisingly large amount of codea service that doesnt do much still will add up to a few hundred lines of code. But much of the
code is boilerplate and can be reused. This service has more than 1,100 lines of code (LOC)
(including white space), and demonstrates communicating with clients across named pipes.
If Watts Humphrey (Humphrey 2006) is correct, our sample service probably has 10 to 20
defects, but it was written to the standards of production code, and we hope that you can base
a shipping application on this sample. Along the way, we encountered some lessons from the
School of Hard Knocks involving how you actually work with services on Windows Vista,
and this will hopefully save you from some of the difficulties we experienced. Well also have
a discussion of the various options you might use for your service to communicate with desktop clients.

Services Overview
Windows services are used to run programs that need to operate independently of whether a
user is logged on at a console. If youre familiar with Unix or Linux, services are very analogous to daemons. Although were not going to go into detail about just how services work, it
would be helpful for you to have an overview of how services function. For a full description,
97

98

Writing Secure Code for Windows Vista

look at the Services topic in the Windows SDK documentation, especially the Service
Program Tasks topic.
Services typically run under one of three specially defined service accounts, and can be configured to run as a user account. Service accounts will be covered in the next section. A service
is just a normal executable program, except that it will make a number of special API calls to
register entry points with the service control manager (SCM). Its this authors practice to
write services that will install and remove themselves if invoked with the correct switches and
that run as a service otherwise. This is because you can end up installing and removing your
service many times during the development process, and the CreateService API takes 13 arguments, not counting the handle to the SCM. Its also easier, since well need the service name
in multiple places in our service code.
The first task a service performs in its main function is to register the ServiceMain function
with the service control dispatcher. This is almost all that the main entry point for the application will do, and if multiple services need to be supported within one process, multiple service names and entry points are registered. Whether to run multiple services in one process is
a key decision from the standpoint of security, performance, and reliability. Regardless of how
many services run in the same process, theyll share the same address space, run under the
same service account, and have the same privileges enabled.
ServiceMain calls yet more boilerplate code: the first thing it does is register the control handler for the service. If the service needs to be started, stopped, paused, or process newer controls (like logon events or hardware changes), the control handler function is where this will
happen. The control handler function is called by the service control dispatcher and operates
asynchronously with your services worker threads, so youll need a way for the control handler function to communicate with the thread or threads doing the work. Many implementations use events, but this example uses I/O completion ports, which can be a lot more efficient
than events, largely because wed need a lot of events to properly handle a named pipe and the
control mechanisms, but we can do it all with one I/O completion port.
There are two control handlers defined, and in new code, you should use RegisterServiceCtrlHandlerEx, which allows you to use the newer controls. Once the control handler has been
registered, the service must update its control status to SERVICE_START_PENDING. If you
need to do lengthy initialization, you need to repeatedly call SetServiceStatus with an updated
wait hint to let the SCM know that your service hasnt hung during start-up. Be careful to only
send updates when youre really making progressjust sending updates in a loop can have
some nasty side effects on the operating system. Speaking of start-up, many services start on
boot, and there are new options that allow your service to start just after boot, which tends to
improve the users overall experience. Check the most recent Windows SDK for details on
this. If the initialization doesnt take much time, go ahead and set the status to
SERVICE_RUNNING. Once the service status has been set to running, you should then go
ahead and call the function in which youre going to do the bulk of your work. Be sure and
implement any code needed to communicate correctly with your control handler in this

Chapter 5

Creating Secure and Resilient Services

99

function, and make sure that the last thing the function does is to set the service status to
SERVICE_STOPPED, with the appropriate exit code. Once ServiceMain returns and the status
has been set to SERVICE_STOPPED, the service will exit, and if it is the only (or last) service
running in that process, the process will exit as well.

Service Accounts
Services normally run under one of three specially defined service accounts or as an
ordinary user:

Local system

Local service This account has few privileges locally and only amounts to a normal
user for the most part, except for the right to create global objects (SE_CREATE_
GLOBAL_NAME), which can have some interesting implications, and the right to impersonate clients (SE_IMPERSONATE_NAME). Note that if youre only identifying clients,
SE_IMPERSONATE_NAME isnt needed. Across the network, services running under the
local service account will authenticate as the anonymous account, which could be a
problem or a feature, depending on what youre trying to do.

Network service This is the account to use when your service has to authenticate
across the network as the computer account. As of Windows 2000, computer accounts
are just variants on normal user accounts and can be added to ACLs and groups. Computer accounts are in the form of Domain\ComputerName$. Other than network
authentication, network service has the same rights as local service.

Domain or local user account You can run services under any user account that can
log on to the system. Although this is sometimes the right choice, password management can be a problem. The best thing to do if youre going to take this approach is to
make two accounts; put them in an appropriate group; and when password changes are
required, cycle all the services from account A to account B.

Also known simply as SYSTEM, this is the Windows equivalent of the


Unix root account and is the most powerful local account in Windows. Although
administrators could configure their own accounts to do anything the local system
account can do, the local system can do nearly anything by default because the account is
a member of the Administrators group and is granted nearly all privileges, and the privileges are enabled by default. You should only run your service as local system if no other
account will work and if youre willing to do a lot of work to ensure that your service is
secure and wont give users an opportunity to escalate privilege. While it is tempting to
run your service as local system during initial development, you could be setting yourself
up for problems later when you run under a less-privileged account. If you have to run as
local system, read the next section on privileges carefully, and only enable those absolutely needed by your service.

100

Writing Secure Code for Windows Vista

Even though the local service and network service accounts are a huge improvement over running all services as local system, there are still a number of problems. If your service needs
access to some specific resource, that resource ends up getting an ACL entry added for local
service or network service. If any other service running under that account is compromised,
your resource is now available to the attacker. The various services running under these
accounts are also vulnerable to attack by each other. If the attacker is clever (and many are)
and having a good day, they may even find ways to escalate privilege to a local system.
The solution to the problem of setting ACLs for specific service resources is to use a new type
of SID in your access control listthe service SID. The code to set the service SID is simple:
DWORD SetServiceSid( SC_HANDLE hSvc, DWORD dwServiceSidType )
{
SERVICE_SID_INFO SvcSidInfo;
DWORD dwErr = ERROR_SUCCESS;
SvcSidInfo.dwServiceSidType = dwServiceSidType;
if( !ChangeServiceConfig2( hSvc,
SERVICE_CONFIG_SERVICE_SID_INFO,
&SvcSidInfo ) )
{
dwErr = GetLastError();
}
return dwErr;
}

There are three values defined for dwServiceSidType:

SERVICE_SID_TYPE_NONEThis doesnt do anything, and the service will behave like


a legacy service.

SERVICE_SID_TYPE_UNRESTRICTEDThis setting adds the service SID to the


process token for the service. This allows you to ACL resources to your specific service
but doesnt keep your service from accessing other resources that may be
inappropriate.

SERVICE_SID_TYPE_RESTRICTEDThis adds the service SID to the process token, and


it creates a set of restricted SIDs in the token as well. The restricted SIDs placed into the
token are everyone, write-restricted, the logon ID SID, and the service SID.

When a process or thread token contains restricted SIDs, all the access checks must go
through two passes. The first is to see if the normal SIDs enabled in the token grant the
access requested. If access is granted, then a second check is performed to see if access is
granted on the basis of the restricted SIDs. Note that different user accounts could satisfy
both checksfor example, the regular check might be granted because user David has access,
and the second check might be granted because the write-restricted SID also has access.
What this implies is that the SERVICE_SID_TYPE_RESTRICTED option means that your
service can only open resources ACLd to everyone, the specific service SID, and the
write-restricted SID.

Chapter 5
Restricted SIDs

Creating Secure and Resilient Services

Resource ACL

Default Groups

Restricted

Administrators: Full control

Network Service

------------------

-----------------------------

------------------

Service SID

Service SID: Full control

Users

------------------

-----------------------------

------------------

Write-Restricted

Everyone: Read

Everyone

------------------

-----------------------------

------------------

Everyone

Users: Read

Auth. Users

------------------

------------------

Logon ID

Logon ID

101

-----------------Service SID

Figure 5-1

Diagram of an access check against a restricted token.

As an example, the sample service has a debug log file. Because having clients connect to a
named pipe implies that youre implementing a state machine, state transitions can be complex and hard to debug, especially when considering error states. Having a log file gives you
an easy way to print out verbose information about whats happening inside the sample service. When we install and run the service, if we fail to provide a full path to the file, we find
that it gets created in %systemroot%\system32, which requires administrator-level access to
add files, and which the process would have if it were running as local system. A better solution is to put the log file in a handy directory used for temporary filessay, for example,
c:\scratch. Heres how you can give the sample service access to the directory in order to
create the log file:
c:\scratch>cacls . /e /g "NT Service\VistaService":c

If youre not familiar with cacls, what this translates to is add an ACE that grants change
access to this directory (.) to the VistaService service accountassuming youve already
installed the service, which is why we install the service first in our example. Note that while
cacls is still supported on Windows Vista, icacls is a more versatile tool, and should be used
for most ACL editing tasks, although it isnt currently available for older operating systems.
As it turns out, if youre running with SERVICE_SID_TYPE_RESTRICTED, then you can end
up creating named objects that you dont have enough access to. When you create persistent
objects, the ACL will depend on the inherited permissions from the parent directory or registry key. When creating named objects, the permissions are still inherited, but are inherited
from the BaseNamedObjects, and this varies depending on whether it is an event, a named
pipe, or some other object. BaseNamedObjects can be thought of as the root directory for
non-persistent named objects. With most of the objects you can create in Windows, you can
specify a security descriptor at creation time, and if youre using SERVICE_SID_TYPE_
RESTRICTED, you may need to do so. In our sample application, when we set

102

Writing Secure Code for Windows Vista

SERVICE_SID_TYPE_RESTRICTED, it failed to initialize because although the service could


create the first instance of the named pipe, it didnt have the access needed to create additional instances. Other types of objects could have similar problems. Unlike ordinary files
and registry keys, the permissions needed for a service SID will be generated uniquely for each
system and will need to be looked up, which means that youll either need to drop to the
lower-level security APIs, or youd have to look up the SID, translate it to a SID string, and then
use it with your SDDL string. If youre doing initial development, you might find it convenient
to run sc showsid on the service, although wed advise just looking up the SID with LookupAccountName.
One advantage to specifying an ACL when creating an object is that you get to put exactly the
access on the object that you need. This also allows you to avoid having race conditions
between creating something and then subsequently setting permissions. The named pipe we
use in our example was set to system:F, NT Service\VistaService:F, and interactive:Read, and
synchronize, which cant be represented in a very readable form in SDDL, because were using
a user that isnt defined by SDDL, which would have to be represented as an SID string specific to that system. This implies that the flag set to deny network access on the pipe is redundant, since no account that could access the pipe from the network has any access. To see
exactly how this was done, take a look at the CreatePipeDacl function in VistaService.cpp.

Reducing Privileges
An ordinary process has a couple of options in terms of reducing unneeded privileges; for
example, the process could call AdjustTokenPrivileges on initialization, with a parameter of
SE_PRIVILEGE_REMOVED. Unfortunately, AdjustTokenPrivileges is one of the least usable API
calls you could ever encounter. The first problem is that it can succeed without doing anything. Only if it succeeds and GetLastError returns ERROR_SUCCESS did it successfully
adjust all the privileges you asked it to manipulatethis is even true if you only asked it to
change one privilege. If it fails to adjust all the privileges, trying to figure out which privileges
werent adjusted will mean some tricky code: the privileges that worked will end up being
written into the parameter for the previous state. Another annoying aspect of AdjustTokenPrivileges, at least when used to disable privileges, is that it works backward from how a good security operation should behave: it disables known bad and doesnt just enable known good. If
youre clever (and determined), you can write code to obtain the list of privileges available to
the process, then remove only the privileges youd like to keep from your list, and then remove
the remaining privileges.
A second approach would be to try and run the service using a restricted token. Unfortunately, you dont control the SCM code that starts the service process and trying to do this by
hand would be difficult and error-prone. Then theres the fact that CreateRestrictedToken is difficult to use; youre likely to encounter problems, such as being able to create objects that your
process doesnt have enough access to; and you could have problems with COM objects. Additionally, you have the same problem as with AdjustTokenPrivileges in that the API asks for the

Chapter 5

Creating Secure and Resilient Services

103

privileges youd like to disable, not the privileges youd like to keep. We strongly recommend
not taking the CreateRestrictedToken approach in a service, although it may be useful if your
service has to launch helper processes, which is what we did with the Windows Search feature
shipping in Vista. Even so, weve had a number of learning experiences along the way.
Fortunately, a new information level was created for the ChangeServiceConfig2 API, and we
have a relatively easy way to specify the privileges the service needs. Even better, the API takes
the list of privileges you needenable known good, never try to disable known bad. Youll
always forget something, or theyll invent a new, dangerous privilege. It even gets better! The
way that this works in the operating system is that the privileges are kept as a multistring in
the registry under the RequiredPrivileges value, so you could tinker with these on the fly without recompiling your application by using the sc privs command. Our only complaint is that
multistrings are a little tricky, and wed have preferred just passing in a TOKEN_PRIVILEGES
structure, but since you can just use our sample code, this isnt really a problem. Heres the
sample:
DWORD SetServicePrivs( SC_HANDLE hSvc, const WCHAR* wzPrivs[], DWORD cPrivs )
{
// The call to set the privileges for a service requires you to pack
// them into a multi-string, which is a series of strings in the same
// buffer that have a double-null terminator
size_t cchTotal = 0;
DWORD i;
for( i = 0; i < cPrivs; i++ )
{
// Add up the length of all the input strings, including the null
cchTotal += wcslen( wzPrivs[i] ) + 1;
}
// Add one more for the final null
cchTotal++;
SERVICE_REQUIRED_PRIVILEGES_INFO ReqPrivs;
const WCHAR wzMultiStringNull[2] = { '\0', '\0' };
if( cchTotal > 1 )
ReqPrivs.pmszRequiredPrivileges = new WCHAR[ cchTotal ];
else
ReqPrivs.pmszRequiredPrivileges = wzMultiStringNull;
WCHAR* wzTmp = ReqPrivs.pmszRequiredPrivileges;
if( wzTmp != NULL )
{
DWORD dwErr = ERROR_SUCCESS;
if( cchTotal > 1 )
{
for( i = 0; i < cPrivs; i++ )
{
size_t cchPriv = wcslen( wzPrivs[i] ) + 1;
wcscpy_s( wzTmp, cchTotal, wzPrivs[i] );
wzTmp += cchPriv;
cchTotal -= cchPriv;
}

104

Writing Secure Code for Windows Vista


// Set the final null
*wzTmp = '\0';
}
// Now we can set the privilege
if( !ChangeServiceConfig2( hSvc,
SERVICE_CONFIG_REQUIRED_PRIVILEGES_INFO,
&ReqPrivs ) )
{
dwErr = GetLastError();
}
if( cchTotal > 1 )
delete[] ReqPrivs.pmszRequiredPrivileges;
return dwErr;
}
return ERROR_NOT_ENOUGH_MEMORY;
}

You can call the function like this:


const WCHAR* wzPrivs[] = { SE_CHANGE_NOTIFY_NAME,
SE_CREATE_GLOBAL_NAME };
DWORD dwRet = SetServicePrivs( hSvc, wzPrivs, _countof( wzPrivs ) );

Note that this service didnt really require the right to create named objects in the global
namespace, but it was a benign privilege we could add to prove that the code actually works
as advertised with multiple privileges. If you had given an empty list of privileges, youd still
end up with SE_CHANGE_NOTIFY_NAME (right to bypass traverse checking) enabled,
because it is a benign right, and a lot of things will break if you dont have it enabled. Heres a
list of privileges currently defined, along with some commentary specific to services.

High-Level Privileges
Dont enable any of these privileges unless you have a need to do so, and understand why
youre doing it. If you have to have any high-level privileges, try to use them during initialization, and then call AdjustTokenPrivileges to drop them once youve completed initialization.

SeAssignPrimaryTokenPrivilege, which is required to assign the primary process token. In


some circumstances, you may need this when calling CreateProcessAsUsersee the SDK
documentation. The user-friendly text is, Replace a process-level token.

SeAuditPrivilege, which is needed to generate entries in the security log. The security log
now has configurable ACLs, which may be a better approach than assigning this privilege. The user-friendly test is, Generate security audits.

SeBackupPrivilege, which essentially disables access checking on files for the entire
process. Unless youre writing backup software, dont ever enable this privilege. The
user-friendly text is, Back up files and directories.

SeCreatePermanentPrivilege, which is needed to create permanent devices under the


\\Device namespace. This right isnt normally required by user-mode applications and

Chapter 5

Creating Secure and Resilient Services

105

shouldnt be granted to your service. The user-friendly string is Create permanent


shared objects.

SeCreateTokenPrivilege, which is required to create a primary token. This privilege also


seems to have no associated API calls, except NtCreateToken, which isnt documented or
supported in user-mode code. The user-friendly string is, Create a token object.

SeDebugPrivilege, which allows a process to open any other process for debugging. Any
process with this privilege can compromise the operating system and should never be
enabled in any service, except an actual debugger. The user-friendly string is, Debug
programs.

SeEnableDelegationPrivilege, which is typically used to delegate domain administration


tasks. Its unlikely that youd be writing a service that needed this privilege, and its only
meaningful on a domain controller. Any process with this right enabled could have a tremendous effect on the security of the domain. Dont enable this unless youre writing an
application to help manage domains. The user-friendly string is, Enable computer and
user accounts to be trusted for delegation.

SeLoadDriverPrivilege, which is needed to load and unload device drivers. A device driver
can completely compromise the operating system, and this privilege shouldnt be enabled
for any typical service. The user-friendly name is, Load and unload device drivers.

SeManageVolumePrivilege, which is used to call some volume management APIs. If your


service needs this API, leave it enabled. The user-friendly string is, Manage the files on
a volume.

SeRestorePrivilege, which is the companion to the SeBackupPrivilege. It can be used to


overwrite any file, without regard to ACL, and allows you to change the owner of a file.
This is one of the more dangerous privileges and shouldnt be enabled under most circumstances. The user-friendly string is, Restore files and directories.

SeSecurityPrivilege, which is needed to set an SACL (system audit access check), and
enables manipulation of system auditing parameters. Because this privilege has strong
security implications, it is dangerous and should only be used when absolutely required.
In general, it is preferable to use the configurable ACLs on the event logs to delegate the
right to read events than by using this privilege. The user-friendly string is, Manage
auditing and security log.

SeSyncAgentPrivilege, which is needed for a domain controller to synchronize the LDAP


directory. A process with this privilege can read any object or property in the directory,
regardless of ACL. Do not enable this unless absolutely required. The user-friendly name
is Synchronize directory service data.

SeSystemEnvironment, which allows the process to manipulate system environment variables. A process with the ability to manipulate the system environment variables, notably the path settings, can have strong effects on the rest of the system. The user-friendly
string is, Modify firmware environment values.

106

Writing Secure Code for Windows Vista

SeSystemtimePrivilege, which is required to modify the system time of day, although not
the time zone, which is a change for Windows Vista. The system time has implications
for Kerberos tickets, and unless youre replacing the Windows Time service, dont enable
this privilege.

SeTakeOwnershipPrivilege, which is required to assume ownership of an object without


having explicit access. This privilege is typically used to bypass ACLs in cases where
someone has removed administrator access. Like the backup and restore privileges, this
is obviously highly sensitive and shouldnt be granted to ordinary services. The userfriendly name is, Take ownership of files or other objects.

SeTcbPrivilege, which allows a process to act as part of the operating system. Although the
details are somewhat arcane, a process with this right can compromise the operating system and should never be granted to a typical service. Under Windows 2000, this privilege was required to call LogonUser, which led to several escalation of privilege points.
On later version of Windows, you dont need this privilege if you know the users password. The user-friendly string is, Act as part of the operating system.

Benign Privileges
The following privileges typically wont allow someone to compromise the operating system,
but only enable these if you need them. Many of these illustrate our point that disabling
privileges you think may be bad can get you into trouble if you start running on a domain
controller and find your service has privileges you hadnt even known about.

SeChangeNotifyPrivilege, which is always enabled, even if you try to disable it. The userfriendly string is, Bypass traverse checking.

SeCreateGlobalPrivilege, which is needed to create objects in the global namespace. This


right is granted by default to services and will be needed if the service creates named
objects such as events, mutexes, or shared memory sections. If your service doesnt create any named objects, you may be able to drop this privilege. The user-friendly string is,
Create global objects.

SeCreatePagefilePrivilege, which is needed to create page files. There are no documented


user-mode API calls that require this right; thus theres no need for your service to enable
this privilege. The user-friendly string is, Create a pagefile.

SeImpersonatePrivilege, which is needed to impersonate clients. The danger here is to the


client, not the server. If you need to impersonate clients with APIs such as ImpersonateNamedPipeClient, then youll need this privilege enabled. Although as we previously
noted, if all youre doing is identifying the user, this privilege isnt needed. As always, if
you dont require it, drop it. Our sample service, which does use named pipes but
doesnt impersonate, is much less dangerous without this privilege. Another item to
think about is that if your service does impersonate clients, and if it can either regularly
or forceably impersonate a local system process, you could provide an avenue for
escalation of privilege unless youre very careful. The user-friendly string is, Impersonate a client after authentication.

Chapter 5

Creating Secure and Resilient Services

107

SeIncreaseBasePriorityPrivilege, which is needed to change the base priority of a process.


Changing a processs priority is usually a bad idea, but the worst youd typically do with
this one is find new meanings for denial of service. If you think you need this, think
again, and if you still think you need it, enable it. The user-friendly string is, Increase
scheduling priority.

SeIncreaseQuotaPrivilege, which is needed in some cases when calling CreateProcessAsUser and is needed by SetSystemFileCacheSize. The user-friendly name is, Adjust memory quotas for a process.

SeLockMemoryPrivilege, which is used to lock physical RAM. Unless youre writing an


application to diagnose physical memory problems, you probably dont need this privilege enabled. The user-friendly string is, Lock pages in memory.

SeMachineAccountPrivilege, which is needed to join new computers to the domain.


Unless your application is used to delegate domain administration tasks, you wont need
this privilege. The user-friendly string is, Add workstations to domain.

SeProfileSingleProcessPrivilege, which is needed to use some of the performance monitoring features. This privilege would typically have few security implications, but as always,
dont enable it unless required. The user-friendly string is, Profile single process.

SeRemoteShutdownPrivilege, which is needed to shut down a system from the network.


This privilege shouldnt be needed by a service. The user-friendly name is, Force shutdown from a remote system.

SeShutdownPrivilege, which is required to shut down the system. Your service typically
wont need to do this, but the implications are obvious. The user-friendly string is, Shut
down the system.

SeSystemProfilePrivilege, which is needed to acquire profiling information for the system.


Like SeProfileSingleProcessPrivilege, this privilege has few direct security implications,
but it should only be enabled when needed. The user-friendly string is, Profile system
performance.

SeUndockPrivilege, which is needed to undock a laptop. We have a hard time imagining


how to compromise a system because of this privilege, but we have an equally hard time
imagining a service that needs it. The user-friendly string is, Remove computer from
docking station.

SeUnsolicitedInputPrivilege is obsolete; in fact, it was removed in Windows NT 3.5.

Controlling Network Access


In the new firewalling API we covered in Chapter 4, there are some additional capabilities we
can apply to services. One of the drawbacks of the previous firewall capabilities is that permissions can be set either globally or on a per-application basis. If your service binary is uniquely
named, that may not be a problem, but if your base application is svchost.exe, then this can

108

Writing Secure Code for Windows Vista

lead to excessive permissionson my system there are 11 svchost.exe processes running, and
some of them are hosting as many as 20 services.
If youre familiar with COM, the firewalling API is relatively easy to use. There are only three
methods exposed by the INetFwServiceRestriction interface, defined in NetFw.h. There are a
few differences that are worth pointing out, especially considering that all of the examples in
the SDK are in VB script. First of all, in the older firewalling API, you first create a NetFwMgr
object, and call get_LocalPolicy to obtain a INetFwPolicy interface. One might (erroneously)
think that you could obtain an INetFwPolicy2 interface from the NetFwMgr object, or perhaps
call QueryInterface on an INetFwPolicy object to get the interface pointer. Because the SDK
doesnt currently document just how you might get an INetFwPolicy2 pointer, you could try a
number of approachesthis author did. As it turns out, the critical clue is in the header, where
youll find a CLSID defined for INetFwPolicy2. Heres what the code looks like:
INetFwPolicy2* pFwPolicy2 = NULL;
hr = CoCreateInstance( __uuidof(NetFwPolicy2),
NULL, CLSCTX_INPROC_SERVER,
IID_INetFwPolicy2,
(void**)&pFwPolicy2 );

Once you have an INetFwPolicy2 pointer, the next step is to get an INetFwServiceRestriction
pointer that will give access to the following methods:

RestrictServiceenable or disable service networking restrictions

ServiceRestrictedqueries if the service is restricted or not

get_Rulesobtains the rule set that applies to the service

Heres how you can use these methods:


INetFwServiceRestriction* pSvcRestrict = NULL;
if( SUCCEEDED( pFwPolicy2->get_ServiceRestriction( &pSvcRestrict ) ) )
{
// Call methods here
pSvcRestrict->Release();
}

The first two methods are fairly easy to manage:


hr = pSvcRestrict->RestrictService( SvcName, AppPath,
VARIANT_TRUE, VARIANT_TRUE );
if( SUCCEEDED( hr ) )
printf( "RestrictService succeeded\n" );
VARIANT_BOOL fRestricted;
hr = pSvcRestrict->ServiceRestricted( SvcName, AppPath, &fRestricted );
if( SUCCEEDED( hr ) )
printf( "Service is %srestricted\n", fRestricted ? "" : "not" );
else
printf( "ServiceRestricted failed - err = %x\n", hr );

Chapter 5

Creating Secure and Resilient Services

109

Remember that both SvcName and AppPath are BSTR types and will need to be initialized with
SysAllocString and freed with SysFreeString. If your application isnt running with the administrator group enabled, RestrictService will fail with access denied, but the system does nicely
allow you read access when running as an ordinary user.
If you happen to already be familiar with the IEnumVARIANT type, dealing with the firewall
rules is no problem, but if you arent, heres how it works:
INetFwRules* pFwRules = NULL;
hr = pSvcRestrict->get_Rules( &pFwRules );
if( SUCCEEDED( hr ) )
{
long iCount = 0;
hr = pFwRules->get_Count( &iCount );
if( SUCCEEDED( hr ) )
printf( "There are %d rules\n", iCount );
IEnumVARIANT* pEnum = NULL;
hr = pFwRules->get__NewEnum( ((IUnknown**)&pEnum) );
if( SUCCEEDED( hr ) )
{
VARIANT Var;
long i;
for( i = 0; i < iCount; i++ )
{
hr = pEnum->Next( 1, &Var, NULL );
if( SUCCEEDED( hr ) )
{
INetFwRule* pRule = NULL;
// Some error checking omitted for clarity
IUnknown* pIu = (IUnknown*)Var.ppunkVal;
hr = pIu->QueryInterface( __uuidof( INetFwRule ),
(void**)&pRule );
BSTR desc;
hr = pRule->get_Description( &desc );
printf("Rule %d: %S\n", i, (WCHAR*)desc );
pRule->Release();
}
}
}
pEnum->Release();
}

This starts out simply: you just call get_Rules to get an INetFwRules interface, and we can then
straightforwardly get the number of rules. Once you have the count, you can then acquire
your IEnumVARIANT pointer. The tricky bit is remembering that you have to use the ppunkVal
member of the VARIANT structure and then call QueryInterface to get access to the firewall rule
itself. Heres what some sample output looks like:
Service is restricted
There are 2 rules
Rule 0: Block all outbound traffic from service VistaService
Rule 1: Block all inbound traffic to service VistaService

110

Writing Secure Code for Windows Vista

Our sample service has no business wandering around opening random sockets and doing
silly things, so the default rule set works quite nicely. If your service needs to do something
more complex, we covered managing rule sets in Chapter 4.

Communicating with the Desktop


A major security problem in the past has been the fact that the console user and services
shared console 0. One of the problems is that a service could put windows on the desktop,
and the local user could then attack the service with Window messages. Window messages
were created for the older 16-bit versions of Windows and, when ported over to Windows NT,
did not have any security added because the desktop is deemed a trust boundary: any process
running in the same console can communicate with any other process running in the same
console using Windows messages. As a consequence, processes running under different user
contexts could send messages that exploited flaws in either the application itself or in the way
that the windowing subsystem handles messages. The entire class of attacks was publicized as
a shatter attack in a series of papers by Chris Paget (Paget 2002). And although it has been
well known for some time (Microsoft 1994) that there are a number of dangers to running
applications with different user contexts on the same desktop, these dangers are not confined
to Windows systems, and the exact techniques used do vary. It isnt advisable for a service to
put UI on a users desktop; a number of services have used this practice.
More Info

At the time this book was written, the original source URL for Pagets paper
was not working. For a more comprehensive article, see the Wikipedia reference at http://
en.wikipedia.org/wiki/Shatter_attack.)

A second side effect of sharing console 0 between the console user and services is that named
objects can have namespace collisions. If youre familiar with the Saltzer and Schroeder design
principles (Saltzer and Schroeder 1975), this is a failure of the principle of least common
mechanism, which implies that functionality and services provided to multiple users should
have a proper level of separation. Namespace collisions have two consequences: the first is
that you can end up with access controls that are much too open than would be best, and the
second is that name squatting attacks can be launched. For our sample service, if someone
could pre-create the WSC_Vista_Pipe, then instead of getting ridiculous developer excuses,
you could have different rude messages delivered, and worse yet, until impersonation became
a privilege, the process running the imposter pipe could have impersonated the client.
The first step toward resolving the problems with console 0 was to institute a separation of
local versus global namespaces. On Windows XP in fast user switching mode, secondary
logons will create objects in local namespaces; on Windows Server 2003 with terminal services in application server mode, all remote logons create named objects in local namespaces,
although the console user still shares the global namespace with services. Windows Vista
extends this by placing all console logons outside of session 0, even though you could rightly
argue that there is still an incomplete enforcement of least common mechanism. Services do

Chapter 5

Creating Secure and Resilient Services

111

run under a number of different user contexts, and even though services can only be installed
by administrators, scheduled tasks (created only by administrators by default) also run in session 0. Ideally, we should break namespaces into per-user directories, but since all of the applications with potential collisions are controlled by administrators by default, theres a
reasonable performance-security trade-off.

Local and Global Namespaces


Just like persistent named objects have containers (directories and registry keys are two
familiar examples), other named objects (events, mutexes and shared memory sections,
just to name a few) are also created inside a container. The container is \BaseNamedObjects. When all processes were creating named objects in the same place, there were
a number of problems: the first was the possibility of name-squatting attacks. Most of
the time, when we use a named object, we need some other piece of code to be able to
find our object at run time, and its inconvenient to create random names and pass them
out of band. Most developers would just hard-code the object name. If someone wanted
to cause problems, they could just create the object before your process did, things
wouldnt work correctly, and there could be serious security problems in some cases.
The second problem is that creating an ACL for something meant to be used by all the
users, regardless of logon session, is a difficult problem, and you may not be able to do
this very well. For example, Office 2003 used shared memory sections to hold toolbar
information and reduce memory footprint. If the shared memory gets created in the global namespace, it has to be writable by everyone. This wasnt overall the best design, and
a different approach that avoided shared memory was used in Office 2007.
Depending on the version of the operating system, users may have their own namespace
to create named objects in, which avoids the name-squatting problem, and the default
ACL is typically just fine, which avoids another issue. Youll get local namespaces in the
following circumstances:

Windows XPnot domain joined, if youre using fast user switching, and youre
not the first user to log on

Windows Server 2003when in Application Server mode, if youre not the


console user

Windows Vista and laterwill always have a local namespace, unless youre running as a service

We patched Office 2003 to create a much more restrictive ACL on the shared-memory
sections when an available local namespace is found.
Consequently, weve been telling developers for some time not to allow services to interact
with the desktop in an unsafe manner, and these services are now broken. If your service
depends on having the interactive flag set, placing windows on the desktop, and receiving or

112

Writing Secure Code for Windows Vista

sending window messages to and from the console user, then youre going to need to find a
safer way to do these tasks.
Here are some of the options you havethere is no single right answer, and the method you
use depends on what youre trying to do and your performance constraints. A common tradeoff youll see as we present the various options is that the higher the performance of the mechanism, the more difficult it is to secure; conversely, the easier it is to provide security, the lower
the performance will tend to be.

Simple Message Boxes


The supported way to present simple message boxes to a user is to call WTSSendMessage,
which has a set of arguments similar to the familiar MessageBox API. One difference is that you
have two arguments for whether youd like to wait for the user to respond and how long to
wait for a response. Youll also need to call WTSEnumerateSessions to find out which consoles
are active and be sure to check the State member of the WTS_SESSION_INFO structure to
make sure the session is activeremember that your application could be used on a terminal
server as well as a desktop computer. This option gives you both good performance and solid
security, but you have a very limited capability to get information from the console user, and
you dont have any real control over how the information is presented.

Shared Memory
You create a shared memory section by using CreateFileMapping with a first argument of
INVALID_HANDLE_VALUE, which creates a memory section that isnt backed by an actual
file. You can use shared-memory sections as an extremely high performance way to transfer
large amounts of data, and once the section is open, you just read and write memory. The
problems youll face are that synchronizing access is difficult; theres no way built into shared
memory to ensure atomicity. You can utilize events or mutexes to try to coordinate access, but
this depends on well-behaved clientsand thats rarely a good option for security. A second
problem is that you will also have problems setting a correct ACL unless youre essentially
using shared memory as a local broadcast mechanism. Most importantly, theres nothing that
enforces the format of the data, and youll need to ensure that any parsers are extremely
robust. Although we havent tested this, you may also run into the same problem we did with
our sample when we set SERVICE_SID_TYPE_RESTRICTED, and youll need to create an
explicit ACL for the section on creation. Unless you have some unusual performance and
application requirements, wed tend to discourage this approach.

Named Pipes
Pipes are a good choice for service-client communication, especially if your service needs to
perform actions on behalf of the user. Impersonating a client is as easy as calling ImpersonateNamedPipeClient and being sure to always check the return. Once a connection is established,
named pipes also allow the client and server to have privacy for local connections. If you want
to enforce privacy and integrity across the network, your options are to configure IPSec or to

Chapter 5

Creating Secure and Resilient Services

113

use cryptography to protect the data. For reasons well discuss in a moment, named pipes
arent an ideal mechanism for network communications, so you may want to avoid using
named pipes on the network.
Using named pipes is fairly easy: on the server side, you call CreateNamedPipe to create as
many instances of the pipe as the number of clients youd like to support, and then call ConnectNamedPipe to wait on clients to connect. Once connected, you call ReadFile and/or WriteFile to copy data to and from the pipe. The usual set of nonblocking capabilities is present
you can either use overlapped I/O and wait on events, or you can use I/O completion ports.
Using named pipes with events can be a little tricky, especially if you dont want to have one
thread per pipe, which is somewhat wasteful. With a service, wed also need a few events to
deal with control messages. Thus, by the time you get around to dealing with unexpected state
transitions, the whole thing is fairly messy. With an I/O completion port, we can use one port
to deal with all the pipes and control messages at once and serve all of the clients with one
thread. Heres the control handler within the worker thread for our sample service:
if( GetQueuedCompletionStatus( g_hPort, &dwBytes, &CompletionKey,
&pOverlapped, INFINITE ) )
{
if( CompletionKey == ControlKey )
{
// Handle control messages here
switch( dwBytes )
{
case SERVICE_CONTROL_STOP:
goto CleanUp;
case SERVICE_CONTROL_PAUSE:
g_CurrentStatus.dwCurrentState = SERVICE_PAUSED;
if( SetServiceStatus( hStatus, &g_CurrentStatus ) )
{
fPaused = true;
continue;
}
goto CleanUp;
case SERVICE_CONTROL_CONTINUE:
g_CurrentStatus.dwCurrentState = SERVICE_RUNNING;
if( SetServiceStatus( hStatus, &g_CurrentStatus ) )
{
fPaused = false;
continue;
}
goto CleanUp;
default:
WriteLogFile( "Unexpected control", dwBytes );
continue;
}
}
...

As you can see, this is a very simple piece of code. One gotcha to remember is that if you set
the service status to SERVICE_PAUSE_PENDING in the control handler routine, and if you

114

Writing Secure Code for Windows Vista

forget to subsequently set the status to SERVICE_PAUSED, the service control manager will
time out your service and refuse to pass any further control messages to it. Youll end up
restarting the system or killing the process with Task Manager. Note that when you use PostQueuedCompletionStatus to a completion port, all three of the arguments passed in are completely arbitrary: dwBytes, the completion key, and the OVERLAPPED pointer could be
anything that fits into the size being passed. In this case, we used a completion key that was
an index into the arrays used to maintain state for the pipes, and a key of ControlKey
(0xffffffff) could be used to mean we had a special event posted to the port. The pipe handling
code is nearly as simple; the bulk of it follows:
switch( g_PipeState[CompletionKey] )
{
case PipeStateStart:
assert( false );
break;
case PipeStateWaitConnect:
// With a completion port design,
// it's hard to be truly paused
// We could do it with an event, but it's
// more polite to the client to just reject them
if( fPaused )
{
DebugState( g_PipeState[CompletionKey], PipeStateReset );
g_PipeState[CompletionKey] = PipeStateReset;
break;
}
// Let's log the connection info
// This consists of the remote computer name,
// client process ID, and client session ID
// If we wanted to maintain state, we could use these to limit
// the session to one pipe instance.
LogConnectionInfo( g_hServicePipe[CompletionKey] );
if( !WritePipe( g_hServicePipe[CompletionKey],
g_PipeState[CompletionKey],
g_Overlapped[CompletionKey] ) )
{
DebugState( g_PipeState[CompletionKey], PipeStateReset );
g_PipeState[CompletionKey] = PipeStateReset;
}
break;
case PipeStateWritePending:
// To do - add more error checking here
// On success, write completed
DebugState( g_PipeState[CompletionKey], PipeStateWaitDisconnect );
g_PipeState[CompletionKey] = PipeStateWaitDisconnect;
break;
case PipeStateWrite:
DebugState( g_PipeState[CompletionKey], PipeStateWaitDisconnect );
g_PipeState[CompletionKey] = PipeStateWaitDisconnect;
continue;
case PipeStateWaitDisconnect:
continue;
case PipeStateError:

Chapter 5

Creating Secure and Resilient Services

115

fDone = true;
break;
}

The one feature pipes are missing that could make them difficult to use across a network is
that theres no way to know when the client has read all of the data. Once we call WriteFile to
write the data to the pipe, we might assume that when this has returned then the client would
have read the data out of the pipe; thus we ought to be able to call DisconnectNamedPipe to disconnect the client from the pipe. Unfortunately, just because we were able to write data into
the pipe only means that the pipe buffer had room to hold a few bytes. It says nothing about
whether the client has read data and cleared the pipe. What we can do is call ConnectNamedPipe, and the return will tell us if the client has closed the connection on its end. If we wanted
to make our server a little more complex, we could let clients write an ACK into the pipe once
the client was ready for more data, but this still doesnt help us against a misbehaved client
that just opens the pipe and then hangs. If youre familiar with sockets programming, what
wed like to be able to do is to send the client a shutdown message that tells them to get the
data now, or lose it, but thats not available to named pipes.
What can we do to avoid denial of service attacks against our pipe server? There are some
really cool new APIs available that can help with this. Weve demonstrated these in the following code snippet:
void LogConnectionInfo( HANDLE hPipe )
{
char tmp[1024];
WCHAR wzComputerName[256];
ULONG ClientProcessId, ClientSessionId;
if( !GetNamedPipeClientComputerName( hPipe,
wzComputerName,
sizeof( wzComputerName ) ) )
{
wcscpy_s( wzComputerName, _countof( wzComputerName ), L"Unknown" );
}
if( !GetNamedPipeClientProcessId( hPipe, &ClientProcessId ) )
ClientProcessId = 0;
if( !GetNamedPipeClientSessionId( hPipe, &ClientSessionId ) )
ClientSessionId = 0;
}

In this case, we just write the information to the debugging log, largely as an example of how
to use these new functions. GetNamedPipeClientComputerName will fail if the client is local and
will otherwise tell you the name of the remote system. Please remember that all of the naming
systems available are prone to corruption and can be unreliable even when youre not under
attack, but its better than nothingand it will reliably distinguish local and remote.
The next two APIs are more intriguing and allow you to do some interesting things. If you call
GetNamedPipeClientProcessId, then you could do some checking up on that process. For example, say you wanted your desktop client to be the only code to connect to your server. Most of
the current code that were aware of to do this depends on unreliable security by obscurity to

116

Writing Secure Code for Windows Vista

perform some sort of handshake or, worse yet, uses an encrypted stream with a fixed key in
the binaries. This is not encryption, nor is it security. Now that we can reliably get the process
ID on the other end, we can see the path to the process; check the signature on the file given
as the process binary; and, if we wanted to be complete, check the modules loaded in the process. In the case of the sample application, we could have guarded against denial of service
attacks by calling GetNamedPipeClientSessionId and enforcing a rule that each session can only
have one pipe instance running at any time. Now the user could create a denial of service
conditionon only themselves! All three of the previously mentioned APIs also have a server
variant that allows a client to find out the same information about the server end of the pipe.
There are two other ways that we could have guarded against denial of service attacks. The first
would be to impersonate the pipe client long enough to identify the user and then maintain a
per-user pool of pipes. A user could deny itself services, but not other users. The lsass named
pipe uses exactly this scheme, which came about after this author demonstrated an annoying
attack tool against beta versions of Windows 2000. The second approach that could be used if
the pipe accepted anonymous clients would be to maintain a timer on a pipe instance once it
had written its final data into the pipe and then just forcefully drop the client once the time out
expired. If you wanted to get a little more sophisticated, you could only drop timed-out clients
once you ran out of available pipe instances, which might save you from creating problems
with clients on very slow or congested networks or with local clients on a very busy system.
The SDK recommends using FlushFileBuffers to cause the pipe server to block until the client
has read all the data, but were not in favor of servers (or even clients) that make blocking calls.
Named pipes have very good performance characteristics and allow for synchronization, as
well as a solid separation of the various clients, but it places no restrictions on the format of
data passed between the client and the server. You will need to carefully validate any parsers
that deal with data being read from the pipe. As an example, our sample client makes the following mistake:
if( ReadFile( hPipe, wzMsgBuf, 1024, &dwRead, &ol ) && dwRead > 0 )
{
printf( "%S\n", wzMsgBuf );
}

The problem here is that this code makes the assumption that the incoming message is null terminated. If the client connected to an evil server, the printf statement could crash with a read
access violation (AV). A more robust piece of code would call wcslen_s to check and see if a null
was encountered within wzMsgBuf, or simply check that wzMsgBuf[ dwRead-1] was a null character. Being able to validate the data types passed to your service is one of the primary advantages of RPC over named pipes, although at a cost of some additional development time.

Sockets
Sockets are meant to be used in hostile environments and have a full set of protections against
denial of service conditionsnetworks can do some nasty things, even when there arent any

Chapter 5

Creating Secure and Resilient Services

117

attackers causing trouble. We could have easily written the preceding application to work
with a socket listening on the localhost address (127.0.0.1 in IPv4 or 0:0:0:0:0:0:0:1 in IPv6),
and it would not have been prone to denial of service attacks. Although I/O completion ports
and sockets arent overly well documented, theyre a great technique for writing high-performance servers.
What you lose with sockets is the ability to easily authenticate or impersonate clients. This can
be done with the Security Support Provider Interface (SSPI) set of API calls, but SSPI isnt one
of the easier API sets to use. Sockets also have no idea of the process or session that originated
a connection, although the remote server can be determined. We can also do this with some
of the new socket extensions, but it still takes a lot more work than just using a pipe. Sockets,
like named pipes, do nothing to validate whether the incoming data stream is well formed,
and the same advice about making sure your parsers are well hardened applies.

RPC/COM
Remote procedure calls are an extremely robust form of interprocess communication. With
RPC, you get it allbuilt-in authentication, the ability to identify and impersonate clients, builtin functionality to maintain privacy and integrity of network communications, and a rich way
to define the data types being passed. All this and asynchronous capabilities too!
The catch is that RPC programming is difficult, and a specialty area. Its also complex enough
that you can make a lot of mistakes, security and otherwise, when using RPC. We spent
30 pages discussing RPC security issues in the second edition of Writing Secure Code. Not only
is it difficult to program, but RPC is also going to have more overhead than any of the techniques mentioned so far. If all you need to do is something simple, RPC is tremendous overkill.
COM (or DCOM) is just a programmer-friendly wrapper over RPC, and you could quite easily
create a COM server, perhaps with ATL, and then a COM client to talk to the service. You get
all of the features of RPC with much less work on your part. The downside is that you get a lot
more overhead, and you get to worry about random applications trying to instantiate your
server. If you choose this approach, you might want to go back and review our RPC/DCOM
chapter in the second edition of Writing Secure Code. DCOM has a number of security implications and decisions, and you may also need to worry about the client impersonating the server
if you choose to use callbacks (also known as sources and sinks). Lastly, be sure you implement all of your interfaces exactly to specifications; if you dont, an application that can load
arbitrary COM objects may get into trouble if your component misbehaves.

Lessons from the School of Hard Knocks


We had some learning experiences along the way as we created our sample service. The first
is that the SDK recommends using GetModuleFileNameEx to obtain the full path to a running
executable. GetModuleFileNameEx now gives you the path in the form of \Device\
HarddiskVolume1\, not c:\. If you pass this form to CreateService, the service wont start.

118

Writing Secure Code for Windows Vista

We couldnt find a simple way to map the \Device paths to drive letters, so one solution is to
assume that the services current directory is where the binary exists. You can then first call
GetCurrentDirectory, followed by GetModuleBaseName to append the binary name to the path.
Note that simply using argv[0] will only give you what the user typed, not the full path.
Another issue that caused some consternation was that because wed written the service to
install and delete itself from the command line, and because both of these actions require
administrator rights, it would seem to make sense to embed a manifest such as the one we
documented in Chapter 2 and make the application always run as administrator. This works
great as long as youre running the service as local system, but as soon as you try and drop it
down to local service, starting the service returns ERROR_ACCESS_DENIED. Neither sc.exe
nor the Control Panels services applet bothers to tell you just where this access denied error
happensit could be accessing the service control manager or the service itself, or it could
even be that the service fails and sets ERROR_ACCESS_DENIED as the error code. After writing some custom code to step through controlling the service, we observed that it was StartService that failed and that the debugging log was never createdwhich tells us ServiceMain
was never executed. The conclusion is that you should create a Visual Studio command
prompt running as administrator to install and remove your service and not embed a manifest
in a service executable that causes it to always run as administrator.
The third problem we encountered was mentioned previously, but its worth mentioning
again. If you restrict the service processs token, your process may not have enough access to
the objects it creates, and youll need to supply an ACL at creation time. This can be difficult
to debug, because the handle returned when you create something will have full control
access; you can do anything you like with that handle, but if you go to reopen the object to get
a second handle, you can be denied access. Once youve seen the problem, its relatively easy
to fix. If you suspect something like this is the problem, create a SECURITY_ATTRIBUTES
structure, attach an initialized SECURITY_DESCRIPTOR to it, and then call SetSecurityDescriptorDacl to set a NULL DACL with bDaclPresent set to true. If whatever it is now works, you
know it is an ACL problem. You must not leave the code this waythis is for debugging purposes only! You should then set a proper ACL on the object just as we did in the CreatePipeDacl function in the sample. We hope that our documenting these issues will save you some
time and frustration.

Call to Action

Run your service as Local Server or Network Service, not Local System.

Restrict the token for your service. Be sure to work out the ACLs needed for your objects
first!

Use the service account SID in the access controls for the services resources.

Restrict the privileges available to the service.

Chapter 5

Creating Secure and Resilient Services

Create restrictive firewall rules to reduce network attack surface.

Think about how your service will communicate with the desktop, and use correct
mechanisms.

119

References
(Humphrey 2006) Software Engineering Institute: Biography, Watts S. Humphrey. http://

www.sei.cmu.edu/tsp/watts-bio.html.
(Paget 2002) Paget, Chris (aka Foon).Exploiting design flaws in the Win32 API for

privilege escalation, http://web.archive.org/web/20060115174629/http://security.


tombom.co.uk/shatter.html. 2002.
(Microsoft 1994) Microsoft Help and Support. Accessing the Application Desktop from a

Service, http://support.microsoft.com/default.aspx?scid=kb;en-us;115825.
Saltzer, Jerome H, and Michael D. Schroeder.The Protection
of Information in Computer Systems, http://web.mit.edu/Saltzer/www/publications/
protection/.

(Saltzer and Schroeder 1975)

Chapter 6

Internet Explorer 7 Defenses


In this chapter:
Pervasive Defenses. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .122
cURL and the IUri Interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .130
Lock Your ActiveX Control . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .131
Other Things You Should Know About Internet Explorer 7 . . . . . . . . . . . . . . . . . .132
Call to Action . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .133
References. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .134
When it comes to living life on the edge, nothing comes close to the threats posed through
Web browsers. Step back and think about it for a moment. A Web browser interprets a reasonable complex language, HTML, and renders the results. But a Web page can also contain code
in the form of scripting languages such as JavaScript, or richer more capable code such as
ActiveX controls, Flash, Java applets, or managed code applications. Ignore for a moment the
fact that mixing code and data is just bad for security. All this code and data make for an
extremely rich and productive end-user story, but its hard to secure. But were not done yet.
The Web browser can render multimedia objects such as sound, JPEG, BMP, GIF, and PNG
files. Perhaps the GIF files are animated. Many file formats are handed off to helper objects,
called MIME handlers. Examples include video formats rendered by Quicktime, Windows
Media Player, or RealPlayer. This all sounds like a lot of functionality to expose to the Internet.
But were still not done. Next, the Web user can browse any Web site on the planet, and the
server at the other end could be hosting Web pages designed to attack the user. A malicious
Web page could take advantage of many possible attack vectors; some vectors are under the
direct control of the browser and some are not.
In some cases, malware can install on a computer without the user realizing, often referred to
as a Drive-by Download. Such downloads can install malicious code on the computer or
upload sensitive data to an attacker. In most cases, the best a browser can do when faced with
a possible download is ask the user to download or not, depending on the browser settings.
Drive-by downloads often work because the user is an administrator; if the user is a standard
user, then malware would find it much harder to manipulate the operating system.
All this makes for an extremely hostile threat environment. Put simply, browsers are wonderful conduits for attacking users.
One remedy is to simply remove all the mobile code, such as script, Java applets, and so on.
There is one ever-so-small problem with this solution: Its a nonstarter. Imagine if all this code
121

122

Writing Secure Code for Windows Vista

was removed: your online bank would not work; itd be much harder to make an online hotel
reservation or make an online purchase. Users have learned to expect a certain level of functionality, and taking that away would incite riots.
At Microsoft, we recognize that browsers will have security bugs, and attackers want to exploit
them. Hand-to-hand combat with individual browser security bugs is a losing proposition. For
Windows Vista, then, we decided to continue, and substantially enhance, the Internet Explorer
defensive work started in Windows XP SP2. Some of these defenses and changes can be used
by developers building on top of Internet Explorer 7, and others pervade the browser and have
an impact on the way developers build software and how code runs within the browser.
Important

In the previous paragraph we used the words, browsers will have security
bugs. But the problem extends beyond bugs in browsers; if you create any form of browser
extensibility, then your code can be attacked also using the same conduit of attack: the Web.

This chapter is divided in two large sections. The first explains the major Internet Explorer
defenses and how they affect developers. The second portion explains the security features in
Internet Explorer that developers can take full advantage of.
Finally, a third, smaller section that covers some Internet Explorer 7 changes that may pose
issues with your application.

Pervasive Defenses
On Windows Vista, Internet Explorer 7 has many defenses designed to protect the user from
malicious software and malicious Web sites. Some of these defenses also exist in Internet
Explorer 7 on down-level Windows platforms.
User Account Control (UAC) aside, the three prime defenses in Internet Explorer 7 in
Windows Vista are:

ActiveX opt-in

Protected Mode

Data Execution Prevention

ActiveX Opt-in
A critical defense in Internet Explorer 7 is ActiveX opt-in. By default, most previously installed
ActiveX controls will not run inside Internet Explorer until the user opts to use that control the
first time the control is referenced. By disabling most ActiveX controls on the system by default,
Internet Explorer reduces the amount of code that can come under attack while still letting a
user have the powerful experiences you can get with ActiveX content like Adobe Flash.
Users often have controls on their machines they simply dont know they have, so the ActiveX
opt-in capability brings first use to the attention of the user. The net effect to you as a

Chapter 6

Internet Explorer 7 Defenses

123

developer is that when users upgrade their machines to Windows Vista and attempt to use a
control your Web application uses, it will fail until they opt to use the control.

Why Doesnt Microsoft Just Get Rid of ActiveX Controls?


ActiveX controls are not hard to write, but they can be hard to get right. So why doesnt
Microsoft simply get rid of the technology? First, remember that binary extensibility is
part of the HTML standard (W3C 1999). We have thought about removing ActiveX support many times. The problem is that so many companies rely on ActiveX controls to run
their businesses, and many common Web components, such as the Adobe Flash Player,
are implemented as ActiveX controls. But if youre thinking of writing new mobile code,
and you are considering using ActiveX controls, you should really consider writing the
code using .NET. Its much safer.
This first-run prompt does not apply to controls that are deployed via a CAB file referenced
from the OBJECT tag in the Web page. The user will be prompted for consent to install these
controls and will not be prompted again to run.
With that said, it is possible to add your own control to a pre-approved list of ActiveX controls
that will not prompt the user on first use. To add your control, simply add a new key under
HKLM\Software\Microsoft\Windows\CurrentVersion\Ext\PreApproved; the name of the key is
your controls GUID. You would typically set this key from an elevated install process.
Do not add your control to the pre-approved list if the control is not meant to be used from a
Web page, and do not add it to the list if the control has previously been kill-bitted
(Microsoft 2006a).
Table 6-1 shows the changes made to ActiveX control installation through various versions of
Internet Explorer.
Table 6-1

Various ActiveX Scenarios in Internet Explorer

Scenario

IE6

IE6 Windows XP
SP2

IE7 Windows XP
SP2

IE7 Windows
Vista

Unsigned ActiveX
downloads

Blocked silently

Blocked silently

Blocked silently

Blocked silently

Signed ActiveX
downloads

Prompt

Blocked and Info


bar notification

Blocked and Info


bar notification

Blocked and Info


bar notification

Preinstalled
ActiveX controls

Run silently

Run silently, policy Blocked and Info


can be changed
bar notification

Blocked and Info


bar notification,
and will prompt
for elevation during installation

Now lets switch focus to developer best practices.

124

Writing Secure Code for Windows Vista

Protected Mode
Of all the defenses in Internet Explorer 7 in Windows Vista, Protected Mode is probably the
biggest architectural changeits the newest too. Protected Mode relies on Integrity Levels in
Windows Vista, which we covered in depth in Chapter 2, User Account Control, Tokens, and
Integrity Levels. In short, the browser process facing the Internet and rendering all that complex and potentially dangerous markup and code runs at low integrity because the content
can never be trusted.
Note

Protected Mode is an example of defense in depth, but it is not a panacea.

In general, HTML content should not behave any differently when Protected Mode is enabled.
Things get a little trickier for extensibility products such as ActiveX controls, toolbars, and
browser helper objects that may need to write to the file system or registry. Most, if not all,
write operations to the operating system will behave differently when Protected Mode is
enabled because Internet Explorer is running at low integrity, and the majority of Windows
Vista objects are labeled at medium or higher integrity.
Note

Protected Mode is disabled if Internet Explorer is started by selecting Run as


administrator.

Table 6-2 outlines some of the new function calls in Internet Explorer that help extensibility
components behave correctly when Protected Mode is enabled. To use these functions you
must include <iepmapi.h> and link with iepmapi.lib.
Table 6-2

Internet Explorer 7.0 Protected Mode Helper Functions

Function

Comments

IEIsProtectedModeProcess

Determines if IE is running in Protected Mode or not.

IEShowSaveFileDialog

Displays the Save File dialog box. The process that displays
the dialog box is not the low-integrity Internet Explorer, it
is a sister process running at medium integrity. If the
dialog operation succeeds, your code must free the path
buffer (lppwstrDestinationFilePath) with CoTaskMemFree.

IEGetWriteableFolderPath

Returns a path the user can write to from Protected Mode.

SHGetKnownFolderPath

Technically not an IE API, this function returns the path to


the low-integrity application data folder.

(FOLDERID_LocalAppDataLow, . . .)
IESaveFile

Saves the file selected during the previous call to


IEShowSaveFileDialog.

IEGetWriteableHKCU

Returns a handle to a registry location under HKCU


writable from low integrity.

Chapter 6

Internet Explorer 7 Defenses

125

Table 6-2 Internet Explorer 7.0 Protected Mode Helper Functions


Function

Comments

IEIsProtectedModeURL

Determines if Protected Mode will be enabled for the URL.


By default, sites in the Trusted Sites zone do not have
Protected Mode enabled.

IELaunchURL

Launches an instance of Internet Explorer with the


correct Protected Mode setting. Use this rather than
CreateProcess.

The IEShowSaveFileDialog function is interesting because the dialog is created by a mediumintegrity helper process named IEUser.exe rather than by the low-integrity IExplore.exe rendering content from the Internet. The reason for launching the dialog from a higher-integrity
process is to let users get their jobs donea browser that does not allow users to save files
would be frustrating to use for most users, and a low-integrity process cannot save files to anywhere useful or convenient. Note the user must initiate the file save operation.
The following code shows how to use some of the new APIs to write data from an application
hosted in the browser to a location in the users registry that can be written to by low-integrity
Internet Explorer.
HRESULT WriteHKCUSetting(__in_z wchar_t *pwszKey,
__in_z wchar_t *pwszValue,
__in_z wchar_t *pwszData) {
BOOL bIsProtected = FALSE;
HRESULT hr = IEIsProtectedModeProcess(&bIsProtected);
if (SUCCEEDED(hr) && bIsProtected) {
HKEY hLowKey = NULL;
hr = IEGetWriteableHKCU(&hLowKey);
if (SUCCEEDED(hr)) {
HKEY hMyKey = NULL;
DWORD dwDisposition = 0;
LONG lRes = RegCreateKeyEx(
hLowKey,
pwszKey,
0L,
NULL,
REG_OPTION_NON_VOLATILE,
KEY_SET_VALUE,
NULL,
&hMyKey,
&dwDisposition);
if (ERROR_SUCCESS == lRes) {
lRes = RegSetValueEx(hMyKey,
pwszValue,
NULL,
REG_SZ,
(CONST BYTE*)pwszData,
wcslen(pwszData + 1));
hr = HRESULT_FROM_WIN32(lRes);
RegCloseKey(hMyKey);

126

Writing Secure Code for Windows Vista


} else {
hr = HRESULT_FROM_WIN32(lRes);
}
// Close the low-integrity handle
RegCloseKey(hLowKey);
}
} else {
// IE not in protected mode
}
return hr;
}

And the following code will launch IE in the correct mode for the URL.
HRESULT LaunchIE(__in_z LPCWSTR pszURL) {
PROCESS_INFORMATION pProcInfo;
HRESULT hr = IELaunchURL(pszURL, &pProcInfo, NULL);
if (SUCCEEDED(hr)) {
CloseHandle(pProcInfo.hProcess);
CloseHandle(pProcInfo.hThread);
}
return hr;
}

Important

Please do not attempt funky tricks to attempt to bypass Protected Mode.


Doing so may, in fact, only break your application if Microsoft updates Protected Mode in the
future. If you have a specific problem that you dont seem able to fix, speak to Microsoft.

Debugging Internet Explorer 7 and Protected Mode


The Microsoft Application Compatibility Toolkit 5.0 includes support for debugging many
Internet Explorer 7 issues, particularly Protected Mode issues. You can download the tool
from Microsoft as part of the Microsoft Application Compatibility Toolkit 5.0 (Microsoft
2006b). At the time we wrote this, you have to download and install the .NET Framework 1.1
too because Windows Vista includes .NET Framework 2.0. Finally, the download Web page
will tell you that you need to install Microsoft SQL Server 2005 Express. If all you want to do
is run the Internet Explorer toolset, then you dont need the database engine. Figure 6-1
shows the test tool in action.

Data Execution Prevention (DEP)


DEP was discussed in detail in Chapter 3, Buffer Overrun Defenses, but to save you from
flipping back to that chapter, heres the short version. Almost every buffer that takes advantage of a buffer overrun enters the system as data and then is executed like code. DEP can help
stop the code from executing in the first place. Most CPUs today support DEP, as does
Windows Vista, and most Windows Vista system processes are DEP-enabled. But there are
some processes that may not work correctly when DEP is enabled. Unfortunately, one of those

Chapter 6

Internet Explorer 7 Defenses

127

applications is Internet Explorer. The reason DEP is not enabled by default is that Internet
Explorer, like all modern graphical browsers, can host other software such as Java applets and
various plug-ins and objects, and many of these applications fail when DEP is enabled
because they may have self-modifying code or use just-in-time (JIT) compilation.

Figure 6-1

Using the Internet Explorer Compatibility Test Tool to analyze Protected Mode failures.

Note

Applications that use older versions of the Active Type Library (ATL) also fail to run
correctly when DEP is enabled because an ATL-generated function thunks on the fly. You
should make sure you update your code to use ATL version 8.0 or higher. You can enforce
this by adding this line early in your code: assert(AtlGetVersion(NULL) >= 0x0800);

You can enable DEP in Internet Explorer by performing these steps:


1. Right-click the Internet Explorer icon.
2. Select Run as administrator and enter an administrators username and password, or
click Allow if your account is a member of the Administrators group.
3. Click Tools | Internet Options.
4. Click the Advanced Tab.
5. Check Enable memory protection to help mitigate online attacks. If this option is grayed
out, you need to launch Internet Explorer as an administrator.
6. Restart the browser.

128

Writing Secure Code for Windows Vista

Figure 6-2 shows the dialog box.

Figure 6-2

Enabling DEP in Internet Explorer 7.

At the time of writing, two of the major non-Microsoft tools used in Internet Explorer, Adobe
Flash Player v9.0.28.0 and Adobe Acrobat Reader v8.0.0, had just been released, and they
both support DEP and run correctly in Internet Explorer when DEP is enabled.

A Short DEP Experiment


Try this little experiment, which assumes your computer is configured to use DEP. Compile
and run this code; its a variant of some sample code used in Chapter 3.
// from metasploit
unsigned char scode[] =
"\xfc\xe8\x44\x00\x00\x00\x8b\x45\x3c\x8b\x7c\x05\x78\x01\xef\x8b"
"\x4f\x18\x8b\x5f\x20\x01\xeb\x49\x8b\x34\x8b\x01\xee\x31\xc0\x99"
"\xac\x84\xc0\x74\x07\xc1\xca\x0d\x01\xc2\xeb\xf4\x3b\x54\x24\x04"
"\x75\xe5\x8b\x5f\x24\x01\xeb\x66\x8b\x0c\x4b\x8b\x5f\x1c\x01\xeb"
"\x8b\x1c\x8b\x01\xeb\x89\x5c\x24\x04\xc3\x31\xc0\x64\x8b\x40\x30"
"\x85\xc0\x78\x0c\x8b\x40\x0c\x8b\x70\x1c\xad\x8b\x68\x08\xeb\x09"
"\x8b\x80\xb0\x00\x00\x00\x8b\x68\x3c\x5f\x31\xf6\x60\x56\x89\xf8"
"\x83\xc0\x7b\x50\x68\x7e\xd8\xe2\x73\x68\x98\xfe\x8a\x0e\x57\xff"
"\xe7\x63\x61\x6c\x63\x2e\x65\x78\x65\x00";
typedef void (*RunShell)( void );
int _tmain(int argc, _TCHAR* argv[]) {
PVOID pBuff = VirtualAlloc(NULL,4096,MEM_COMMIT,PAGE_READWRITE );

Chapter 6

Internet Explorer 7 Defenses

129

if (pBuff) {
memcpy(pBuff,scode,sizeof scode);
// Well uncomment this code later
// DWORD dwOldProtect = 0;
// VirtualProtect(pBuff,sizeof scode,PAGE_EXECUTE_READ, &dwOldProtect);
RunShell shell = (RunShell)(void*)pBuff;
(*shell)();
VirtualFree(pBuff,0,MEM_RELEASE);
}
return 0;
}

When you run it, youll see an instance of calc.exe pop-up. As you can probably guess, thats
what the shellcode defined in scode does. There is no buffer overrun in this code; the code is
simply calling into a buffer copied onto the heap.
Next, link the code with the /NXCOMPAT linker option. If youre using Visual Studio 2005,
then you need to perform the following steps:
1. Right-click the project name, and then click Properties.
2. Expand Configuration Properties.
3. Expand Linker.
4. Click Command Line.
5. In the Additional options text box, type /NXCOMPAT.
6. Click OK.
Now rerun the code, and youll get an access violation on the line that calls the shellcode,
(*shell)(). This is DEP working, assuming that your processor supports DEP, and has it
enabled in the BIOS.
But lets say your code has a valid reason to run data even though you have linked with
/NXCOMPAT. You can mark the virtual memory as readable and executable by uncommenting the two commented lines of code in the previous sample code. Recompile the code and
run it, and youll see calc.exe appear. Your application is still protected by DEP, but now your
code has a little more flexibility, and can run correctly even with DEP enabled. The call to
VirtualProtect marks the virtual memory used to launch calc.exe as readable and executable,
so the code runs correctly. Of course, you should use VirtualProtect sparingly and not for all
memory allocations (only for those allocations must run code), otherwise DEP will offer little,
if any protection.
Important

At some point in the future DEP will be enabled by default in 32-bit Internet
Explorer. Its enabled by default for 64-bit Internet Explorer today, but you should prepare for
the 32-bit eventuality now.

130

Writing Secure Code for Windows Vista

cURL and the IUri Interface


Making a trust decision based on the name of something is rife with error because there are so
many ways to name resources, and such comparisons are often subject to canonicalization
errors (Howard and LeBlanc 2003). Making a trust decision based on elements of a URI is
fraught with risk because there are so many ways to canonicalize URIs. That said, all Web
browsers make security decisions based on URIs. The real underlying risk with canonicalization is when more than one piece of code interprets a name differently. This impedance mismatch can lead to one unit of code thinking a name is good while anther portion of code
thinks the name is bad. To alleviate this problem, the Internet Explorer 7 team migrated IE
itself to use only one canonicalizer and then made that code available for all to use. That code
is named the consolidated URL parser or cURL (Microsoft 2006c).
Note

Although a few exceptions exist for compatibility purposes, cURL is generally aggressive
at rejecting URIs that are invalid under the latest standard covering the subject (RFC 3986).

To use cURL in your browser component, you should include <urlmon.h>, link with
urlmon.lib, and make sure you have the following line in your code before you load urlmon.h:
#define_WIN32_IE_WIN32_IE_IE70

The following code shows a basic way to use the cURL interface to create a URI, and break it
down into its requisite components.
int wmain(int argc, wchar_t* argv[]) {
if (argc != 2) {
wprintf(L "Please enter a URL");
return -1;
}
wchar_t *pwszUri = argv[1];
// Create an IUri object from the URI
IUri *pIUri = NULL;
HRESULT hr = CreateUri(
pwszUri,
Uri_CREATE_ALLOW_RELATIVE,
0,
&pIUri);
if (SUCCEEDED(hr)) {
BSTR bstrSchemeName;
if (SUCCEEDED(pIUri->GetSchemeName(&bstrSchemeName))) {
wprintf(L "Scheme: %s\n",bstrSchemeName);
SysFreeString(bstrSchemeName);
}
BSTR bstrHost = NULL;
if (SUCCEEDED(pIUri->GetHost(&bstrHost))) {
wprintf(L "Host : %s\n",bstrHost);
SysFreeString(bstrHost);
}

Chapter 6

Internet Explorer 7 Defenses

131

DWORD dwPort=0;
if (SUCCEEDED(pIUri->GetPort(&dwPort))) {
wprintf(L "Port : %d\n ",dwPort);
}
}
if (pIUri)
pIUri->Release();
return 0;
}

Note also there is a new COM interface named IInternetSecurityManagerEx2 that accepts IUri
objects; use it instead of IInternetSecurityManagerEx and IInternetSecurityManager.
Various URL parsing functions, such as the following are now considered deprecated in favor
of cURL if you are using cURL:

InternetCrackUrl

ParseURL

UrlIsOpaque

UrlGetPart

UrlGetLocation

InternetCanonicalizeUrl

UrlCanonicalize

UrlUnescape

UrlEscape

InternetCreateUrl

CreateURLMoniker

The performance impact of cURL is generally no different from using other canonicalization
functions, but fewer function calls and therefore fewer redundant escape operations can lead
to performance benefits.
There are potential application compatibility side effects because Internet Explorer 7 uses
cURL internally and has much stricter URL parsing; some nonvalid URL sequences that used
to work may no longer work in script or browser add-ons.

Lock Your ActiveX Control


This defense has nothing to do with Windows Vista, but it is worth repeating. You should lock
an ActiveX control to its originating site with SiteLock (Microsoft 2007) or your own custom
code to check the control is instantiated from your Web site. If you want to use your own code
rather than take on a SiteLock dependency, you can call IWebBrowser2:: get_LocationURL to

132

Writing Secure Code for Windows Vista

get the originating URL, and pass it to cURL or one of the legacy URL cracking APIs and then
do a string comparison to determine if the control is activated from your Web site or not.

Other Things You Should Know


About Internet Explorer 7
A number of small, but important changes have been made to Internet Explorer 7 that may
affect your Web-based applications or your users.

Clipboard Access Is Disabled


This is a big change from prior versions of the browser. HTML code can no longer access the
clipboard using the window.clipboardData object without user consent in the Internet Zone.
Of course, an ActiveX control can access the clipboard, and ActiveX vendors implement their
own security protections for programmatic clipboard access in different Zones. Note that userinitiated clipboard actions, for example the oncut, oncopy, and onpaste handlers will not
prompt the user.

Script URLs
Embedding script into a URL attribute works differently in Internet Explorer 7. For example,
the following snippet:
<html>
<a href= "javascript:alert('click');">click</a>
</html>

is transparently evaluated by the browser as:


<html>
<a href= "#" onclick= "alert('click');">click</a>
</html>

Notably, the following use of a script URI no longer executes at all because JavaScript is not a
valid source for IMG tags:
<html>
<IMG SRC= "javascript:alert('bang');">
</html>

Good-bye PCT and SSL2 (and Good Riddance), Hello AES!


Private Communication Technology (PCT) was developed by Microsoft and Visa International to correct a number of weaknesses in SSL2 (Murray 2000). SSL2 has some very serious
security weaknesses and these are addressed in SSL3 and its successor, TLS. Because SSL3 is
now broadly available and because it addresses the issues in SSL2, PCT has been deprecated

Chapter 6

Internet Explorer 7 Defenses

133

and no longer supported in Windows Vista. And because SSL2 is so weak, it is disabled by
default in Internet Explorer 7. If your Web site uses only SSL2 or PCT, it will fail to work correctly with Internet Explorer 7, and in fact it wont work in Mozilla FireFox v2 either. If your
Web site requires SSL2, its time to upgrade the configuration! Windows Vista also disables
the weak 40- and 56-bit ciphers while adding new ciphers, including 256-bit Advanced
Encryption Standard (AES).

Window Origin
This change will have little effect on most Web applications. Any dialog box that pops up from
Internet Explorer 7 will automatically have an address bar with the originating address, which
helps the user determine if the Web page has come from a trusted Web site or not.
Tip

Do you want a good tool to view or manipulate HTTP headers and related information? Then use Fiddler from www.fiddlertool.com.

Call to Action
If theres only one thing you take away from this chapter, its this: if you build an extensibility
feature for a Web browser, such as an ActiveX control, a toolbar, or a browser helper object,
you need to realize that your code is as at risk as the browser itself. With that in mind you
should perform all the action items in Chapter 3, including these:

Compile with /GS

Link with /NXCOMPAT, /SAFESEH, and /DYNAMICBASE.

If your code generates code on the fly, or attempts to execute code from data, then you should
still link with /NXCOMPAT but call VirtualProtect(. . .,PAGE_EXECUTE_READ, . . .) on the
memory region you want to execute. You may also need to call the new Internet Explorer 7
Protected Mode file and registry function calls if you want to save data to the operating system
without virtualization.
Do not expect usersand do not force usersto disable Protected Mode to run code from your
Web site. If your code does not run in Protected Mode, even after making updates to the code,
then suggest that users add your site to the Trusted Sites zone. This will turn off Protected
Mode for your site.
Consider migrating URI canonicalization or parsing code to use cURL. Microsoft does not
expect developers to migrate code to use cURL overnight, however. But you should plan to do
so over time.
If your Web server still uses SSL2 or PCT, you should upgrade to use SSL3; otherwise your
Web applications will not work correctly with Internet Explorer 7 or FireFox 2.0.

134

Writing Secure Code for Windows Vista

As discussed in Chapter 2, you should code sign your ActiveX controls before they are
released to customers.
If your control is intended to be used only from your site, consider sitelocking the implementation so that it cannot be used from other Web sites. The best tool for the job is SiteLock.
Some functionality is removed or changed in Internet Explorer 7 in the name of security, such
as clipboard access and script URLs, so you should perform a complete application compatibility test of your Web application.

References
WC3 Recommendation. 13 Objects, Images, and Applets, http://www.w3.org/
TR/html4/struct/objects.html.

(W3C 1999)

(Microsoft 2006a) Microsoft Help and Support. How to Stop an ActiveX Control from Run-

ning in Internet Explorer, http://support.microsoft.com/kb/240797. December 2006.


Microsoft Application Compatibility Toolkit 5.0. http://
technet.microsoft.com/en-us/windowsvista/aa905072.aspx. TechNet.

(Microsoft 2006b)

(Howard and LeBlanc 2003) Howard, Michael, and David LeBlanc. Writing Secure Code,

2nd ed., Chapter 11, Canonical Representation Issues. Redmond, WA: Microsoft Press,
2003.
IUri Interface. http://msdn.microsoft.com/workshop/networking/moniker/
reference/ifaces/IUri/IUri.asp. MSDN.

(Microsoft 2006c)

(RFC 3986) Internet Engineering Task Force, Network Working Group. RFC 3986: Uniform

Resource Identifier (URI): Generic Syntax, http://www.ietf.org/rfc/rfc3986.txt.


January 2005.
(Microsoft 2007) SiteLock, http://msdn.microsoft.com/archive/default.asp?url=/archive/

en-us/samples/internet/components/sitelock/default.asp. MSDN.
(Murray 2000) Murray, Eric. SSL Server Security Survey, http://www.megasecurity.org/

Info/ssl_servers.html#1.2. July 2000.

Chapter 7

Cryptographic Enhancements
In this chapter:
Kernel Mode and User Mode Support . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .136
Crypto-Agility. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .136
New Algorithms in CNG . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .139
Using CNG. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .140
CNG and FIPS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .142
Improved Auditing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .143
Something Missing from CNG . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .144
SSL/TLS Improvements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .144
Root Certificates in Windows Vista . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .148
Deprecated Crypto Features in Windows Vista. . . . . . . . . . . . . . . . . . . . . . . . . . . . .148
Call to Action . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .148
References. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .149
All versions of Windows add new cryptographic capabilities, but in most cases its a few new
APIs or new algorithms. Windows Vista is different because Microsoft added a modern cryptographic infrastructure, called Cryptography API: Next Generation (CNG), that supports
new APIs and offers kernel and user mode support, better support for crypto-agility, new
cipher suites [most notably Suite B (NSA 2005)], and improved auditing.
Microsoft also improved Secure Sockets Layer and Transport Layer Security (SSL/TLS) with
new cryptographic algorithms and support for Suite B. In this chapter we will explain all these
subjects and more.
Important

We want to point out that this chapter will not explain how cryptographic
algorithms work, and this chapter will most certainly not turn you into a cryptographer!

Windows Vista supports the following user mode cryptographic interfaces:

CNG

Cryptographic API 1.0 (CAPI 1.0)

Cryptographic API 2.0 (CAPI 2.0)

.NET Framework Cryptography


135

136

Writing Secure Code for Windows Vista

New cryptographic innovation will occur in CNG and .NET, and CAPI 1.0 will eventually be
phased out. CAPI 2.0 will be supported because it is not a superset of CAPI 1.0. One could
argue that CAPI 2.0 is named badly. It is! CAPI 2.0 is a different functionality than CAPI 1.0,
CAPI 2.0 exists to manage and generate X.509 certificates and related standards; it does not
support low-level cryptographic primitives like CAPI 1.0 and CNG do.

Kernel Mode and User Mode Support


One of the most important changes in CNG is the inclusion of user mode and kernel mode
APIs. In prior versions of Windows, technologies such as Cryptographic API (CAPI) were user
mode only, and kernel mode cryptography required a totally different set of APIs, such as the
Microsoft Kernel Mode Cryptographic Module (Microsoft 2000). This is a big boon for developers who create user-mode and kernel-mode code because there is only one set of APIs to
remember.
Youll also notice that CNG has two distinct sets of functions names. The NCrypt* functions
deal with key management, key persistence and key isolation, and some public key cryptographic operations (because private keys cannot leave the cryptographic boundary if your
application wants key isolation). The BCrypt* functions are the low-level cryptographic primitives that run in-process with your applications, and keys are not stored, they are ephemeral.

Crypto-Agility
Cryptographic algorithms are constantly under attack on two fronts. The first is the ceaseless
increase in processor speed, making it more feasible that algorithms can be cracked in reasonable times, and the second is from ongoing cryptographic research that continually finds
weaknesses in algorithms. A good example of this research is weaknesses found in some
major hash functions; MD4, MD5 are now considered utterly insecure because of poor collision resistance, and SHA-1 is showing signs of serious weaknesses. In fact, Microsoft has
banned the use of MD4 and MD5, and SHA-1 in new code except for backward compatibility or if the algorithm is used in an industry standard, or in applications where the minimum Windows platform is anything older than Windows Vista.
More Info NIST has some excellent guidance about the use of SHA-1: Federal agencies
should stop using SHA-1 for digital signatures, digital time stamping and other applications
that require collision resistance as soon as practical, and must use the SHA-2 family of hash
functions for these applications after 2010. After 2010, Federal agencies may use SHA-1 only
for the following applications: hash-based message authentication codes (HMACs), key derivation functions (KDFs), and random number generators (RNGs). Regardless of use, NIST
encourages application and protocol designers to use the SHA-2 family of hash functions for
all new applications and protocols. (NIST 2006).

Chapter 7

Cryptographic Enhancements

137

Sometimes policy dictates the need for new algorithms; a great example would be the U.S.
federal Suite B requirements. If your application does not understand Suite B, but your
competitors do, then your lack of crypto-agility could mean lost sales.
The biggest mistake developers make is hardcoding the algorithm name in the code; if the
algorithm is weak and needs to be replaced, then the code has to be fixed to use the new
algorithm, data structures need to be updated, and finally a product update needs to be issued
to customers. In some cases, this kind of work can cause incompatibilities with older file
formats. The following code snippet, using Cryptographic API (CAPI), is an example of code
that is not crypto-agile because it has an embedded algorithm identifier:
if(CryptDeriveKey(hProv, CALG_DES, hHash, CRYPT_EXPORTABLE, &hKey)) {
// Encrypt data
}

A good example of crypto-agility is SSL and TLS, which securely negotiate cryptographic
algorithms between the server and client. If an algorithm is deemed weak, a simple algorithm
policy setting at the server or client will prevent that algorithm from being used. We discuss
these settings later in the chapter.
Note

It could be argued that SSL and TLS really dont have good crypto-agility because
the underlying random number generators are hardcoded to use SHA-1 and MD5!

Crypto-Agility in CNG
There are three major areas of improvement in CNG that make agility easier. First, all
cryptographic constants are strings rather than numeric constants. In CAPI, all cryptographic
algorithms are predefined in wincrypt.h. This makes it very hard to extend cryptographic functionality to suit your applications needs. Adding a custom symmetric encryption algorithm to
CAPIfor example, Serpent (Anderson 1999)is not easy. But this all changes in CNG
because you can use any string constant you want to define your algorithm, and when your
application attempts to use your algorithm, CNG will load the crypto-provider that registered
that name.
Crypto-agility in CNG extends beyond cryptographic primitives; you can also plug in custom
cipher-suites for SSL and TLS or customer envelopes for CMS and custom certificate elements.
Documentation outlining the steps to install and register a CNG add-in can be found in the
CNG SDK. The core function that adds a new add-in is BCryptAddContextFunctionProvider:
#define BCRYPT_SERPENT_ALGORITHM L"SERPENT"
status = BCryptAddContextFunctionProvider(
CRYPT_LOCAL,
NULL, // Default context
BCRYPT_CIPHER_INTERFACE,

138

Writing Secure Code for Windows Vista


BCRYPT_SERPENT_ALGORITHM,
L"Serpent Provider",
CRYPT_PRIORITY_TOP);

The second area of agile improvement is that unlike CAPI, CNG does not require Microsoft to
sign the implementation. A cryptographer can create a CNG cryptographic provider. When
implementing a CNG provider, you need only implement the necessary functionality. For
example, if you implement a Serpent provider, then the provider does not need to implement
signing or hashing functions because Serpent is only a symmetric encryption algorithm.
Finally, it is possible for an application to query CNG for supported algorithms, based on certain criteria, if needed. The following code shows how to dump all primitive cryptographic
algorithms:
PROVIDER_REFS pProviders = NULL;
DWORD dwBufSize = 0;
const DWORD dwFlags = CRYPT_ALL_FUNCTIONS | CRYPT_ALL_PROVIDERS;
for (DWORD dwInterface = BCRYPT_CIPHER_INTERFACE;
dwInterface <= BCRYPT_RNG_INTERFACE;
dwInterface ++) {
NTSTATUS ret = BCryptResolveProviders(
NULL,
dwInterface,
NULL,
NULL,
CRYPT_UM,
dwFlags,
&dwBufSize,
&pProviders);
if (NT_SUCCESS(ret) && pProviders) {
printf("dwInterface = %d\n", dwInterface);
for (DWORD k=0; k < pProviders->cProviders; k++) {
PCRYPT_PROVIDER_REF pProv = pProviders->rgpProviders[k];
printf("\tFunction = %S\n", pProv->pszFunction);
printf("\tProvider = %S\n", pProv->pszProvider);
// dump property names
for ( DWORD j = 0; j < pProv->cProperties; j++)
printf("\tProperty %d = %S\n",
j,
pProv->rgpProperties[j]->pszProperty);
printf("\n");
}
BCryptFreeBuffer(pProviders);
pProviders = NULL;
}
}

Important

Note that only administrators can install a CNG provider.

Chapter 7

139

Cryptographic Enhancements

New Algorithms in CNG


CNG offers a number of newer algorithms; most notably and probably most importantly, is
support for Suite B. Tables 7-1 and 7-2 outline all the algorithms supported by the default
CNG providers in Windows Vista.
Table 7-1

Cryptographic Algorithms in Windows Vista CNG

Algorithm

#define

Standard

RC2

BCRYPT_RC2_ALGORITHM

RFC2288

RC4

BCRYPT_RC4_ALGORITHM

AES

BCRYPT_AES_ALGORITHM

FIPS 197

DES

BCRYPT_DES_ALGORITHM

FIPS 46-3, FIPS 81

DESX

BCRYPT_DESX_ALGORITHM

3DES

BCRYPT_3DES_ALGORITHM

FIPS 46-3, FIPS 81,


SP800-38A

3DES-112

BCRYPT_3DES_112_ALGORITHM

FIPS 46-3, FIPS 81,


SP800-38A

MD2

BCRYPT_MD2_ALGORITHM

RFC 1319

MD4

BCRYPT_MD4_ALGORITHM

RFC 1320

MD5

BCRYPT_MD5_ALGORITHM

FC 132

SHA-1

BCRYPT_SHA1_ALGORITHM

FIPS 180-2, FIPS 198

SHA-256

BCRYPT_SHA256_ALGORITHM

SHA-384
SHA-512

Allowed Suite
by SDL? B?
Yes*
Yes

Yes

FIPS 180-2, FIPS 198

Yes

Yes

BCRYPT_SHA384_ALGORITHM

FIPS 180-2, FIPS 198

Yes

Yes

BCRYPT_SHA512_ALGORITHM

FIPS 180-2, FIPS 198

Yes

Yes

RSA (encryption)

BCRYPT_RSA_ALGORITHM

PKCS#1 v1.5 and


v2.0.

Yes

RSA (signing)

BCRYPT_RSA_SIGN_ALGORITHM

PKCS#1 v1.5 and


v2.0.

Yes

Diffie-Hellman

BCRYPT_DH_ALGORITHM

PKCS#3

Digital
Signature
Algorithm

BCRYPT_DSA_ALGORITHM

FIPS 186-2

*RC4 is only allowed after full cryptographic review.


Note

SHA-256, SHA-384, and SHA-512 are collectively referred to as SHA-2 and are available on Windows Vista (in CAPI and CNG) and Windows Server 2003 (in CAPI), and all supported Windows platforms via the .NET Framework.

140

Writing Secure Code for Windows Vista

Elliptic Curve Cryptographic Algorithms in Windows Vista CNG

Table 7-2
Algorithm

#define

Standard

Elliptic Curve Digital Signature


Algorithm with Prime-256 curve

BCRYPT_ECDSA_P256_ALGORITHM

FIPS 186-2, X9.62

Elliptic Curve Digital Signature


Algorithm with Prime-384 curve

BCRYPT_ECDSA_P384_ALGORITHM

FIPS 186-2, X9.62

Elliptic Curve Digital Signature


Algorithm with Prime-521 curve

BCRYPT_ECDSA_P521_ALGORITHM

FIPS 186-2, X9.62

Elliptic Curve Diffie-Hellman


Algorithm with Prime-256 curve.

BCRYPT_ECDH_P256_ALGORITHM

SP800-56A

Elliptic Curve Diffie-Hellman


Algorithm with Prime-384 curve.

BCRYPT_ECDH_P384_ALGORITHM

SP800-56A

Elliptic Curve Diffie-Hellman


Algorithm with Prime-521 curve.

BCRYPT_ECDH_P521_ALGORITHM

SP800-56A

Note

All of the above are approved for use in the SDL, are Suite B compliant, and are new

to CNG.

CNG also supports two kinds of random number generators (RNG), and both are allowed
under SDL: BCRYPT_RNG_ALGORITHM and BCRYPT_RNG_FIPS186_DSA_ALGORITHM.
Most applications should use the former, but if you are using DSA, then you should use the
latter. Both RNGs conform to FIPS 186-2 and FIPS 140-2.

Using CNG
What follows are a series of small code function outlines that show how to use CNG to perform
various cryptographic tasks. Consider the examples as pseudo-code using real API names. The
intent is not to demonstrate every possible algorithm or cryptographic operation, nor do we
want to show huge swaths of code; rather, we want to show the general API call order.
Note

CAPI1 APIs dont have access to CNG providers and keys, but CNG has access to
CAPI1 keys used by Microsoft Cryptographic Service Providers.

The Windows Vista Software Development includes complete CNG samples in the samples/
security/CNG folder. There is also a separate CNG SDK available that includes samples and
documentation relating to CNG configuration and installing CNG plug-ins (Microsoft 2006a).
In all cases you must include <bcrypt.h> and link your code with bcryt.dll. Also, CNG returns
various status values defined in ntstatus.h. You may also need to add this macro to your code:
#ifndef NT_SUCCESS
#
define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)
#endif

Chapter 7

Cryptographic Enhancements

141

Encrypting Data
BCryptOpenAlgorithmProvider(&hAlg,...)
BCryptGetProperty(hAlg,BCRYPT_BLOCK_LENGTH,&dwBlockSize,...)
Allocate buffer, rounding up to next block size.
BCryptGetProperty(hAlg,BCRYPT_OBJECT_LENGTH,&cbKeyObjectLen,...)
Allocate buffer for key object.
BCryptGenerateSymmetricKey(hAlg,&hKey,...)
BCryptEncrypt(hKey,...)
Data is now encrypted
BCryptDestroyKey(hKey)
BCryptCloseAlgorithmProvider(hAlg,0)
Deallocate buffers

Note that like CryptAcquireContext in CAPI, BCryptOpenAlgorithmProvider is a reasonably


expensive function call, and it might be helpful to cache the return handle in your code rather
than constantly opening and closing a provider.

Hashing Data
BCryptOpenAlgorithmProvider(&hAlg,...)
BCryptGetProperty(hAlg,BCRYPT_OBJECT_LENGTH,&cbHash,...)
Allocate buffer for hash
BCryptCreateHash(hAlg,&hHash,...)
BCryptHashData(hHash,...)
BCryptFinishHash(hHash,...)
Use the hash data
BCryptDestroyHash(hHash)
BCryptCloseAlgorithmProvider(hAlg,0)
Deallocate buffers

MACing Data
Creating a message authentication code is exactly the same as creating a hash, but there are
two differences.
1. The last argument to BCryptOpenAlgorithmProvider should be BCRYPT_ALG_HANDLE_
HMAC_FLAG.
2. The fifth and sixth arguments to BCryptCreateHash are the secret MAC key and the length
of the MAC key. So the function call looks like this:
BCRYPT_ALG_HANDLE hAlg = NULL;
NTSTATUS status = STATUS_UNSUCCESSFUL;
status = BCryptOpenAlgorithmProvider(&hAlg,
GetPreferredHmacAlg(),
NULL,
BCRYPT_ALG_HANDLE_HMAC_FLAG)))

The call to GetPreferredHmacAlg is not a CNG function; its a function you would provide to get
the preferred HMAC base algorithm, perhaps from a configuration setting.

142

Writing Secure Code for Windows Vista

Generating Random Numbers


Because the code to generate random data is very small, we have included all the code here:
BCRYPT_ALG_HANDLE hRngAlg = NULL;
if (BCryptOpenAlgorithmProvider(&hRngAlg,
BCRYPT_RNG_ALGORITHM,
NULL,
0) == STATUS_SUCCESS) {
BYTE buf[32];
if (BCryptGenRandom(hRngAlg,
buf,
sizeof buf,
0) == STATUS_SUCCESS) {
// We have the random data
}
BCryptCloseAlgorithmProvider(hRngAlg,0);
hRngAlg = NULL;
}

CNG and FIPS


The Federal Information Processing Standards (FIPS) at http://www.itl.nist.gov/fipspubs/
define standards and guidelines that are developed by the National Institute of Standards and
Technology (NIST) for U.S. federal computer systems. Five standards pertinent to this chapter
are as follows:

FIPS 140-2: Security Requirements for Cryptographic Modules

FIPS 180-2: Secure Hash Standard (SHS)

FIPS 186-2: Digital Signature Standard (DSS)

FIPS 197: Advanced Encryption Standard (AES)

FIPS 198: The Keyed-Hash Message Authentication Code (HMAC)

These standards define cryptographic requirements and cryptographic algorithms to be used


in U.S. federal information systems. It is possible to configure Windows Vista to use only
FIPS-mandated algorithms by performing these steps:
1. Open MMC.
2. Add the Group Policy Objects Snap-in.
3. Navigate to Local Computer Policy, Computer Configurations, Windows Settings, Security Settings, Local Policies, Security Options.
4. Enable the following option: System cryptography: Use FIPS compliant algorithms for
encryption, hashing, and signing.

Chapter 7

Cryptographic Enhancements

143

Now heres the caveat. This setting only affects the protocol suites used by SSL/TLS and .NET
code. The following C# will fail with a System.InvalidOperationException exception because it is
using a non-FIPS compliant algorithm, MD5.
MD5CryptoServiceProvider hash = new MD5CryptoServiceProvider();
byte[] result = hash.ComputeHash(ASCIIEncoding.UTF8.GetBytes(message));

From a CNG application, it is possible to determine if the FIPS requirement is enabled or not
by using the BCryptGetFipsAlgorithmMode function.

Improved Auditing
To help comply with certain Common Criteria requirements, various key operations are
audited. Enter the following command from an elevated command-prompt to configure key
auditing in Windows Vista.
auditpol /set /subcategory:"other system events" /success:enable /failure:enable

Note

The U.S. Government Protection Profile for Single-level Operating Systems in Environments Requiring Medium Robustness v1.67, 5.1, defines security audit requirements,
including those related to cryptographic key use (NSA 2003).

Various keys operations, such as creation, deletion, and key access will yield events such as
those shown in Figure 7-1.

Figure 7-1

Audit event created when an RSA key is accessed from CNG.

You can view these entries in the Security log of the Windows Event Viewer.

144

Writing Secure Code for Windows Vista

Something Missing from CNG


Just like CAPI, CNG is missing a password-based key derivation function (RFC 2898). Essentially, you should never use a password directly to encrypt data; rather, you should derive the
final key from the original password. This usually involves performing a cryptographic operation, such as a hash, thousands of times (the iteration count) on the original key. Think of the
iteration count as a Moores Law compensator. As machines get faster, you can simply
increase the iteration count to compensate for machine speed and slow the attacker down.
The .NET Framework includes support for PBKDF, such as the Rfc2898DeriveBytes class. Here
is sample code showing how you can use the class:
string password = args[0];
byte[] salt = new byte[16];
new RNGCryptoServiceProvider().GetBytes(salt);
Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(password, salt, 50000);
byte[] key = pdb.GetBytes(16);
byte[] iv = pdb.GetBytes(16);
Console.WriteLine("Key: " + Convert.ToBase64String(key));
Console.WriteLine("IV : " + Convert.ToBase64String(iv));

CNG does include a very flexible key derivation function, BCryptDeriveKey, that can be used
to derive keys the same way SSL3, TLS1, and CMS do, but its not a password-to-key function.
It is hoped this will be addressed in a future version of CNG.

SSL/TLS Improvements
There are two major improvements to SSL/TLS in Windows Vista. The first is newer cipher
suites, including support for the Suite B algorithms: elliptic-curve encryption, SHA-2, and
AES. Windows Vista supports the cipher suites shown in Table 7-3.
SSL/TLS in Windows Vista also supports the following cipher suites, but they can only be used
from code by calling the SSL/TLS Security Support Provider (such as TLS1SP_NAME) directly.

TLS_RSA_WITH_NULL_MD5

TLS_RSA_WITH_NULL_SHA

As mentioned earlier in this chapter, you can also add a custom cipher suite by a writing an
SSL/TLS provider plug-in.
Second, Windows Vista makes it easier to configure the cipher suites you are willing to support for SSL/TLS; its simply a policy setting. You can set the policy by performing the
following steps:
1. Open mmc.exe.
2. Click File and then Add/Remove Snap-in.
3. Scroll down to and select the Group Policy Object Editor.

Chapter 7

Cryptographic Enhancements

145

4. Click Add.
5. Select remote computer by clicking Browse, or Finish, to access the local computer.
6. Click OK and then OK again.
7. Open the following nodes: Local Computer Policy, Computer Configuration, Administrative Templates, and then Network.
8. Click the SSL Configuration Settings node.
9. Double-click the SSL Cipher Suite Order setting.
10. Click Explain to learn how to modify this setting.
Table 7-3

New SSL / TLS Cipher Suites in Windows Vista

TLS_RSA_WITH_AES_128_CBC_SHA

TLS_DHE_DSS_WITH_AES_128_CBC_SHA

TLS_RSA_WITH_AES_256_CBC_SHA

TLS_DHE_DSS_WITH_AES_256_CBC_SHA

TLS_RSA_WITH_RC4_128_SHA

TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA

TLS_RSA_WITH_3DES_EDE_CBC_SHA

TLS_RSA_WITH_RC4_128_MD5

TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA_P256 SSL_CK_RC4_128_WITH_MD5
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA_P384 SSL_CK_DES_192_EDE3_CBC_WITH_MD5
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA_P521 TLS_RSA_WITH_NULL_MD5
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA_P256 TLS_RSA_WITH_NULL_SHA
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA_P384 TLS_RSA_WITH_DES_CBC_SHA
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA_P521 TLS_DHE_DSS_WITH_DES_CBC_SHA
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA_P256

TLS_RSA_EXPORT1024_WITH_RC4_56_SHA

TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA_P384

TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA

TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA_P521

TLS_DHE_DSS_EXPORT1024_WITH_
DES_CBC_SHA

TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA_P256

TLS_RSA_EXPORT_WITH_RC4_40_MD5

TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA_P384

SSL_CK_DES_64_CBC_WITH_MD5

T LS_ECDHE_RSA_WITH_AES_256_CBC_SHA_P521

SSL_CK_RC4_128_EXPORT40_WITH_MD

SSL/TLS Revocation Checking and OCSP


Certificate Revocation List (CRL) checks are available in all currently supported versions of
Windows. When an application wants to verify a certificate is not revoked, the application
reads the Certificate Revocation List Distribution Point (CDP) from the certificate. A CRL
lookup could use HTTP, LDAP, or simple remote file access to fetch the CRL. The CRL is a
digitally signed blob that includes revoked certificate serial numbers. If the serial number of
the certificate being validated is in the CRL, then the certificate is revoked, and the application
should take appropriate action.
Windows Vista also supports Online Certificate Status Protocol (OCSP), as defined in RFC
2560 (RFC 2560). OCSP has advantages and disadvantages over using CRLs because they

146

Writing Secure Code for Windows Vista

can get large, but an OCSP lookup is small. The major disadvantage is that for OCSP to work,
the application must be online, but CRLs can be cached, which means a CRL lookup may not
necessarily be remote.
Note

Windows Longhorn Server includes OCSP server support.

The really good news is OCSP support is transparent in Windows Vista if the certificate being
checked includes an appropriate Authority Information Access (AIA) URL. Like a CDP, an AIA
can include a URL or URLs to access to determine if the certificate has been revoked or not.
Figure 7-2 shows a valid AIA in a Web server certificate.

Figure 7-2

A Verisign certificate that includes an AIA for OCSP use.

If your application calls CertGetCertificateChain to verify a certificate, and the certificate


includes an appropriate AIA, then Windows Vista will use OCSP to verify the certificate before
checking the CRL if a CDP is present in the certificate. You can change this policy by performing the following steps:
1. Open mmc.exe
2. Add the Group Policy Object Editor Snap-in.
3. Expand the Local Computer Policy node.
4. Expand the Computer Configuration node.
5. Expand the Windows Settings node.

Chapter 7

Cryptographic Enhancements

147

6. Expand the Security Settings node.


7. Click the Public Key Policies node.
8. Double-click the Certificate Path Validation Settings Properties object type.
9. Click the Revocation tab.
Figure 7-3 shows the revocation policy dialog box.

Figure 7-3

Certificate revocation policy settings in Windows Vista.

An application may fail to access a CDP or the OCSP URL, in which case functions like CertGetCertificateChain will fail and return a CRYPT_E_REVOCATION_OFFLINE error. If your
application is in a bind, what should it do if it cannot verify that a certificate is revoked or not?
We cant give a 100 percent applicable answer because it depends on the nature of your application. If it is a sensitive application, or an application running in a sensitive environment,
then you should fail operations related to the certificate use.
The certutil -url command-line tool can be used to interactively verify a certificate using a CRL
or OCSP.
Note

You can look at important certificate-related events in the Event Viewer. Open the
Event Viewer, and expand Applications and Services Logs, then expand Microsoft, then
expand Windows and finally expand CAPI2.

148

Writing Secure Code for Windows Vista

Root Certificates in Windows Vista


Youll notice that very few root certificates are installed during a fresh Windows Vista setup. In
fact, the only root certificates installed are those required to boot the OS. By default, if a root
certificate is untrusted, Windows Vista will use Windows Update (WU) to see if the root certificate is one of the hundred or so root certificates that were installed with Windows XP. If the
root certificate is on WU, the operating system will copy the root certificate and install it
silently. But what if you dont want this to happen? What if you only want to trust the root certificates you trust? All you need to do is disable Windows Vistas automatic root certificate
update capability by following these steps:
1. Open mmc.exe and add the Local Computer Policy Snap-in.
2. Navigate to Computer Configuration | Windows Settings | Security Settings | Public
Key Policies.
3. Click the Certificate Path Validation Settings object.
4. Click the Network Retrieval tab.
5. Check Define these policy settings.
6. Uncheck Automatically update certificates in the Microsoft Root Certificate
Program.

Deprecated Crypto Features in Windows Vista


The following cryptographic features are deprecated or not supported on Windows Vista:

The XEnroll and SCdEnrl COM objects are no longer included with Windows Vista; you
should use the CertEnroll API instead (Microsoft 2006b).

Beginning with Windows Vista, CAPICOM, the COM interface to CryptoAPI, is no


longer supported. If you want to use a higher-level API, you should use the .NET
Framework.

WinVerifyTrust should no longer be used for certificate verification; rather you should use
the CertGetCertificateChain function call instead.

Call to Action

Review your use of cryptographic functionality to determine if you need Suite B


algorithms or not. If you do, then CNG is the way to go.

Determine how much of your code uses hard-coded algorithm names, start to migrate
the code to read from a configuration store, and then write the cryptographic settings
information to the document meta-data.

Chapter 7

Cryptographic Enhancements

149

Evaluate which weak algorithms should be removed from your code and replaced with
strong algorithms, or better yet stronger algorithms, making your code crypto-agile at
the same time.

Some cryptographic functionality is now deprecated in Windows Vista, and you should
start to migrate to user the newer, more robust functionality instead.

References
National Security Agency. Fact Sheet NSA Suite B Cryptography, http://www.
nsa.gov/ia/industry/crypto_suite_b.cfm.

(NSA 2005)

(Microsoft 2000) Microsoft Kernel Mode Cryptographic Module, http://www.microsoft.

com/technet/archive/security/topics/issues/fipsdrsp.mspx. October 2000.


Computer Security Resource Center. Cryptographic Toolkit: Secure Hashing,
http://csrc.nist.gov/CryptoToolkit/tkhash.html.

(NIST 2006)

(Anderson 1999)

Serpent Homepage. http://www.cl.cam.ac.uk/~rja14/serpent.html.

(Microsoft 2006a) CNG Software Development Kit. http://www.microsoft.com/downloads/

details.aspx?FamilyID=1ef399e9-b018-49db-a98b-0ced7cb8ff6f&DisplayLang=en.
National Security Agency. U.S. Government Protection Profile Single Level
Operating Systems for Medium Robustness Environments, http://www.niapccevs.org/
pp/draft_pps/pp_draft_slos_mr_v1.67.cfm October 2003.

(NSA 2003)

RSA Laboratories. Network Working Group, Request for Comments :2898.


PKCS #5: Password-Based Cryptography Specification Version 2.0, http://
www.ietf.org/rfc/rfc2898.txt. September 2000.

(RFC 2898)

(RFC 2560) Entrust Technologies. Network Working Group, Request for Comments 2560.

X.509 Internet Public Key Infrastructure Online Certificate Status ProtocolOCSP,


http://www.ietf.org/rfc/rfc2560.txt. June 1999.
(Microsoft 2006b)

aa374863.aspx.

Certificate Enrollment API. http://msdn2.microsoft.com/en-gb/library/

Chapter 8

Authentication and Authorization


In this chapter:
Windows CardSpace and Information Cards . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .151
Graphical Identification and Authorization (GINA) Changes . . . . . . . . . . . . . . . . .159
Owner SID Changes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .160
Call to Action . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .161
References. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .161
When most people think of security, they think of cryptography, authentication, and authorization. Of course, security is much more than this, but knowing this does not reduce the
importance of the three most well-known security technologies. We have already covered
some of the Windows Vista cryptographic enhancements in Chapter 7. In this chapter, we
focus on some of the new advances in authentication and authorization in Windows Vista,
most notably Windows CardSpace and Information Cards, Graphical Identification and
Authorization (GINA) changes, and a change we made to the way Owner SIDs work in access
controls lists (ACLs.)

Windows CardSpace and Information Cards


Windows CardSpace is Microsofts implementation of an Information Card system. Simply
put, an Information Card is just a digitally signed XML document used to identify a user. The
core developer support for Information Cards is in the .NET Framework 3.0 included in
Windows Vista or is available as a download for Windows XP SP2 and later and Windows
Server 2003 and later. Support for Information Cards does not require .NET Framework 3.0,
but it certainly makes building Information Card aware systems easier. Underlying Windows
CardSpace are some of the industry-standard WS-* protocols, including:

WS-Security (XMLSOAP 2002)

WS-Trust (XMLSOAP 2005a)

WS-MetadataExchange (XMLSOAP 2006)

WS-SecurityPolicy (XMLSOAP 2005b)

All these protocols are covered by Microsofts Open Specification Policy (Microsoft 2006a),
which means that Microsoft will not enforce any patent or intellectual property rights for the
use of these industry standards, even though Microsoft was instrumental in designing some
of the standards.
151

152

Writing Secure Code for Windows Vista

The benefits of Information Cards for service providers (online merchants, banks, etc.) are
many, including:

Stronger client authenticationEven personal cards are more secure than a simple username and password combination.

Sign-in abandonment reductionOnline merchants do not want users turned away at


the point they must enter their credentials. CardSpace makes this process easier, which
translates into fewer drop-offs and increased spending by customers.

Phishing reductionCardSpace makes it very difficult to mount a successful phishing


attack. We discuss this in more detail shortly.

ConvenienceUsers do not have to remember passwords.

The Information Card Data Flow


There are usually three main parties involved during an Information Card exchange. The user,
also called the subject, must first acquire an Information Card from an Identity Provider using
the providers security token service (STS); this could be any classic card issuer you are
familiar with today, for example, a credit card company or perhaps a digital identity provider
such as VeriSign. It is also possible to issue an Information Card to yourself. Note that no
specialized hardware is required to use Information Cardsunless the user wishes to use a
smartcard.
Next, there is the Relying party, which refers to the entity that wants to know who you are so
they can provide a service to you. In our example, well use a fictitious bank, Woodgrove Bank.
Figure 8-1 shows the information between the communicating parties.
Tip

You might think user-issued Information Cards are of little use. In fact, they are useful
because its quite common for a user to create his or her own identity when visiting a Web
site for the first time and creating an account at that Web site.

Windows CardSpace and Phishing


Information Cards helps mitigate phishing by employing a number of important security techniques, including:

Server authentication

No password to steal! (Seriously!)

PIN-Protect the users Information Cards

Display Information Card use

Lets look at each.

Chapter 8

User

Windows
CardSpace

Authentication and Authorization

Relying Party
(Woodgrove
Back)

153

Identity
Provider

Acquire Information Card


(out of band)
(1) User requests service
(2) Request security policy
(3) Return security policy

(5) Present valid


Information Cards to the
user

(4) Evaluate security


policy of relying party
and find candidate
information cards that
satisfy the policy

(6) Use selects Information


Card
(7) Request security policy
(8) Return security policy
(9) Request security token with required claims
(10) Return token
(11) Send request and
security token
(12) Application response
(13) User gets response

Figure 8-1

The Information Card communicating parties.

Server Authentication
One of the biggest enablers of phishing attacks is poor or nonexistent server authentication;
requiring SSL/TLS server authentication goes a long way to remedying the server authentication problem. All communication between the Windows CardSpace client and the server is
performed using SSL/TLS, but more importantly, Windows CardSpace requires the SSL/TLS
server authenticate correctly to the Windows CardSpace client. In other words, all the appropriate checks are made by Windows CardSpace to make sure the server is who it claims to be.
The checks performed by default are as follows:

Server name the client requests matches the common name in the server certificate.

The server certificate has not been tampered with.

Server certificate is trusted (that is, you trust the certificate issuer).

The date validity is correct.

154

Writing Secure Code for Windows Vista

The certificate key usage includes server authentication.

The certificate has not been revoked (may be a local cached lookup).

No Password to Steal!
When a user provides his Information Cardbased identity to a server, the users password is
never provided to the server. Information Cards do not include a password or any other type
of secret user credential data. This is absolutely critical, because one of the reasons attackers
mount phishing attacks is to harvest unwitting users passwords. Rather, a trusted entity, the
Identity Provider, attests to the users identity.
Also, if the user is using a self-issued Information Card, the key presented to one site is different from the key presented to another site, because the key is derived, in part, from the
servers server authentication certificate.

PIN-Protect the Users Information Cards


A user can PIN-protect her CardSpace information; the PIN is used to encrypt the CardSpace
data, so malware cannot get the users CardSpace data unless it can successfully decrypt the
data. An AES-256 encryption key is derived from the users PIN and a cryptographically
unique 128-bit number called a salt after it is passed through a password-based key derivation
function (using PKCS#5) for 1,000 iterations. This value will be increased in future versions of
Windows.

Display Information Card Use


Finally, when an Information Card is selected, Windows CardSpace shows the historical use
of the card and where the Information Card has been used. This is important, because if the
site is fraudulent, and all the prior defenses have failed, the user will see that this card has
never been used at the phishing site.
Lets look at all these defenses in action using a fictitious phishing scam.

CardSpace and PhishingAn Example


Lets assume for a moment that scammers are targeting Woodgrove Bank (www.
woodgrovebank.com) customers to get customer account details such as account numbers
and passwords. Lets also assume that Woodgrove Bank requires Information Card identities
for all customers when they access their online banking data.
The most common way phishers mount a phishing attack is to send an email that looks like
it came from an institution such as Woodgrove Bank, informing the unsuspecting victim that
they need to change their password or view an important documentboth requiring that the
customer enter her credentials. Information Cards cannot help defend against this part of the
attack, but perhaps the users email client can detect the email is fraudulent.

Chapter 8

Authentication and Authorization

155

Lets assume the worst, and the user clicks the bank link in the email. The Web browser
opens, and the user is confronted with a Web site that looks just like the real Woodgrove Bank
Web site. The site probably includes trademark, copyright, and privacy notices, too! In short,
it looks real. But its actually a compromised Web serversomewhere on the Internetthat is
made to look like Woodgrove Bank, and its sole purpose is to harvest account numbers and
passwords of gullible Woodgrove Bank customers.
Again, Information Cards can do nothing here, but perhaps the users browser can. Both Internet Explorer 7 and Mozilla FireFox 2 have support for detecting and notifying users of many
known phishing sites, as does the Netcraft Toolbar for older browsers (Netcraft 2004).
The connection between Windows CardSpace and the Web server must be over SSL/TLS, and
all appropriate SSL/TLS checks are made; otherwise, CardSpace will reject the connection. In
other words, the name of the Web site in the browsers address bar must equal the name in
the certificate, and the certificate must be trusted. This will foil most phishing attacks. This
has a side effect of breaking some Web sites if they choose to use an SSL/TLS certificate that
does not reflect the Web server DNS name. If you want to use Information Cards with your
Web site, you should use a valid X.509 certificate, which includes the sites DNS name in the
certificate common name (CN).
Lets again assume the worst, and the user clicks the option to sign in to the bank, regardless
of any SSL/TLS warnings issued by the browser. If the user enters her credentials, the rogue
Web site now has the users logon information. But things are difficult for the phisher. First,
for the user to enter her credentials, the logon page must look just like the Windows CardSpace login because Woodgrove Bank uses CardSpace. It is, of course, possible to spoof a user
interface, but how will the attacker know what cards the user has and display the users cards
correctly? Also, how will the attacker know the visual secrets chosen by the user? By visual
secrets we mean the image and text associated with each Information Card (see Figure 8-2).
Again assuming the worst, the attack site does not spoof the users CardSpace environment but
instead invokes the users CardSpace environment; the user clicks on an Information Card
and enters a PIN to unlock the card. The attacker does not get the users credential, even if the
credential is a password. Information Cards rely on a trusted third party to assert the users
identity. The importance of this last point cannot be overstated. The real bank and the
attacker never get the users password. Ever.
The phishing site will simply get, at best, a token that asserts the user is who the user claims
to be. The password is provided to the trusted identity provider, not the phishing site, or the
valid site for that matter.
Even if the attacker gets the key from a self-issued card, he cannot replay the key against the
real Woodgrove Bank because when a self-issued card is used, the key is derived (in part) from
the certificate used by the Web site. Given that the site is different (phisher versus Woodgrove), the generated key is not the same.

156

Writing Secure Code for Windows Vista

Figure 8-2

The Windows CardSpace identity selector.

Tip

If you want to see a good technical overview of CardSpace in action, watch the video,
Vittorio Bertocci: WS-TrustUnder the Hood, on Channel9 (Channel9 2006). Vittorio also
has an excellent CardSpace blog (Bertocci 2006) that includes sample code.

Seeing Information Cards in Action


If you want to get started quickly using Windows CardSpace, create a new self-issued Information Card (go to Control Panel [not in classic view], User Accounts, Windows CardSpace) and
then point your browser at https://woof.bandit-project.org/wiki/index.php?title=Special:
Userlogin, and then click on the Login with the Information Card (Simple) button. Follow the
prompts. If all goes well, you should see your username in the Information Card appear as
your login name.

Whats in an Information Card?


Information Cards are digitallysigned XML data structures that represent information about
the user, known as an assertion. The Information Card is provided by an issuer, and assertion
details include the users name, date of birth, email address, and so on. Note that assertions are
optional and need not contain any personal or private data, but there needs to be at least one
assertion in the token. The assertions are described using the Security Assertion Markup
Language (SAML) (OASIS 2006), which is a XML-based industry standard. Microsofts use of
SAML is also covered by Microsofts Open Specification Policy (Microsoft 2006a). When a mer-

Chapter 8

Authentication and Authorization

157

chant wants a user to identify itself, the merchant can request certain assertions, and the Windows CardSpace Identity Selector will allow the user to select an Information Card that
supports the required claims.

Programmatically Accessing Information Cards


As we already mentioned, Information Cards support is made easier by using the .NET
Framework 3.0 that ships in Windows Vista; the .NET Framework 3.0 is also available as a
download for Windows XP SP2 and later and Windows Server 2003 and later.
Information Card functionality is in the System.IdentityModel namespace exported from the
C:\Program Files\Reference Assemblies\Microsoft\Framework\v3.0\System. IdentityModel.dll assembly. Most times, you do not need to explicitly add the assembly reference
because the Windows Communication Foundation (WCF) will call the assembly
implicitly.
If you want to experiment with Information Cards, you should download the Accepting
information cards in your website (in C#) sample code from the Windows CardSpace
Web site (Microsoft 2006a).
Tip

We had a couple of problems installing the code on Windows Vista. If you get an
exception like this, Relying Party Certificate thumbprint not specified, then you should
explicitly register capicom by typing regsvr32 capicom.dll in the sample code bin directory.

A Web site can trigger the Windows CardSpace identity selector with HTML code like this:
<html xmlns="http://www.w3.org/1999/xhtml" >
<body>
<form id="logonform" method="post" action="login.aspx">
<button type="submit">Sign in with your Information Card</button>
<object type="application/x-informationcard" name="xmlToken">
<param name="tokenType" value="urn:oasis:names:tc:SAML:1.0:assertion" />
<param name="issuer"
value="http://schemas.xmlsoap.org/ws/2005/05/identity/issuer/self" />
<param name="requiredClaims"
value="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname
http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname
</object>
</form>
</body>
</html>

Note the object tags type is application/x-informationcard, and the parameters define
what claims the Web site requires from the user, as well as the valid issuer(s). In this case, the
Web site will accept self-issued Information Cards that assert the users given name and
surname.

158

Writing Secure Code for Windows Vista

The login page can then get the data from the users Information Card using code like this:
string xmlToken = Request.Params["xmlToken"];
if (xmlToken == null || xmlToken.Equals("")) {
// Handle Error there is no token
} else {
Token token= new Token(xmlToken);
string givenname = token.Claims[ClaimTypes.GivenName];
string surname = token.Claims[ClaimTypes.Surname];
string email = token.Claims[ClaimTypes.Email];
}

Detecting Information Card Support in the Browser


Detecting browser support for Information Cards requires only a small amount of client-side
JavaScript. If the following function returns true, then your Web site can dynamically display
a Please sign in with your information card interface.
<script language=Javascript>
function AreCardsSupported() {
var IEVer = -1;
// regexp used to get browser version info
var regMSIE = "MSIE ([0-9]{1,}[\.0-9]{0,})";
if (navigator.appName == 'Microsoft Internet Explorer')
if (new RegExp(regMSIE).exec(navigator.userAgent) != null)
IEVer = parseFloat( RegExp.$1 );
// Look for IE 7+ and support for Information Cards.
if( IEVer >= 7 ) {
var obj = document.createElement("object");
obj.setAttribute("type", "application/x-informationcard");
return ( ""+obj.issuerPolicy != "undefined" ) ? true : false;
}
// not IE (any version)
if( IEVer < 0 && navigator.mimeTypes && navigator.mimeTypes.length) {
// check to see if there is a mimeType handler.
x = navigator.mimeTypes['application/x-informationcard'];
if (x && x.enabledPlugin)
return true;
// check for the IdentitySelector event handler is there.
var event = document.createEvent("Events");
event.initEvent("IdentitySelectorAvailable", true, true);
top.dispatchEvent(event);
if( top.IdentitySelectorAvailable == true)
return true;
}
return false;
}
</script>

Chapter 8

Authentication and Authorization

159

The Windows CardSpace Private Desktop


Windows has the concept of multiple desktops; usually a user sees only twothe logon
desktop and his usual workspace desktop. There is one logon desktop, and each user has his
own desktop ACLd to the user, which prevents one user from tampering with another users
session. Windows CardSpace creates its own private desktop for use by CardSpace Identity
Selector. The purpose of this is to help reduce the chance that certain kinds of spoofing
attacks can occur, most notably screen-scraping attacks.

CardSpace Summary
Nearly two-thirds of this chapter is dedicated to Windows CardSpace and its implementation
of the Information Card identity technology, so we want to wrap this section up with a short
summary. We feel Information Cards are a very real phishing defense, but we need more
people to adopt the technology in both clients and servers. Today, there is Information Card
support for many non-Microsoft platforms and technologies, and the list of supported is
growing quickly. We highly recommend that you acquaint yourself with Kim Camerons blog
(Cameron 2006) and the Windows CardSpace resource Web site (Microsoft 2006a) and
consider adding Information Card support alongside other identity technologies your system
presently supports.

Graphical Identification and


Authorization (GINA) Changes
Lets be honest: this section affects a very small number of people because few developers
build authentication modules for Windows. The only Independent Software Vendors (ISVs)
who do build authentication modules are those who want to leverage other authentication
schemes not natively supported by Windows, such as biometric devices and hardware security tokens. So, if youve never heard of a function called WlxLoggedOutSAS, skip this section
altogether! Trust us on this.
One of us (Michael) built a GINA module for Windows NT 4 for a banking customer to interface with its IBM mainframes Resource Access Control Facility (RACF) authentication
system. It wasnt fun. In short, a brave developer must build a custom replacement for
MSGINA.DLL, which is very problematic because this DLL is tightly coupled with the operating system, and service pack changes could make custom GINAs unstable at times, requiring
constant maintenance.
Windows Vista includes a new model for implementing code to support custom user authentication methods called the Credential Provider model; its still not fun to use, but its a lot
easier, better designed, and more robust than the older model in previous versions of the
operating system. A credential provider is an in-process COM object that displays its own user
interface on the Windows Vista logon desktop and collects credentials to be used for custom
authentication.

160

Writing Secure Code for Windows Vista

If you want to learn more about this area, you should review Windows Vista Credential
Providers (Microsoft 2006c) and become familiar with the ICredentialProvider interface
through the available sample code (Microsoft 2006d).

Owner SID Changes


In Windows, an object owner has full control of the object; even if the owner is denied access
to the object, she can still access it because an objects owner implicitly has the READ_
CONTROL and WRITE_DAC rights. WRITE_DAC is a powerful right that can be used to change
the objects access control policy. In Windows Vista, this is still true. However, a developer can
change the owner semantics by adding an Owner Rights ACE to an objects discretionary
access control list (DACL) with an access mask that defines what the owner can do.
The Owner Rights SID is new in Windows Vista; the SID is S-1-3-4, and the SDDL constant is
SDDL_OWNER_RIGHTS (OW). It can also be simply declared with:
SID OwnerRightsSid = {
SID_REVISION, 1,
SECURITY_CREATOR_SID_AUTHORITY,
SECURITY_CREATOR_OWNER_RIGHTS_RID };

If youre sure that your code will only run on Windows XP and later, a more robust and nearly
as efficient way to accomplish the same thing is to use CreateWellKnownSid with an argument
of WinCreatorOwnerRightsSid.
When the DACL for the securable object is evaluated during an access operation in Windows
Vista, a check is made for ACEs containing the Owner SID to determine the rights granted to
the objects owner. If the DACL contains no Owner SIDs, the objects owner is granted the
READ_CONTROL and WRITE_DAC rights, as in previous versions of Windows. However, if
the DACL contains one or more Owner ACEs, the access check will use those entries to
determine the owner's rights.
For some customers, this is a very useful feature. For example, an administrator can ensure
that users who create files and folders will not change the intended access control policy on
those resources or that users are unable to change settings on an object they created after they
have been removed from a particular group.
Another example is related to the ability for services to be assigned a service SID in Windows
Vista, as we covered in Chapter 5. Some resource isolation can be achieved by ACLing objects
with a service's SID, but not resources created by the service at run time: they will be owned
by LocalSystem, NetworkService, or LocalService, and hence will be ultimately modifiable by
other instances of such services. By adding an Owner ACE to the ACLs of those resources, we
can prevent other services from accessing resources belonging to our service, because the
other service cant change the access controls.
As a final example, an Active Directory administrator can allow users in a specific group to
create objects under an Organizational Unit (OU) but can then restrict their ability to modify

Chapter 8

Authentication and Authorization

161

or create group objects when removed from that group. This change allows the emulation of
a standard UNIX access control trick: a user can create a file and then not be able to access it
once it has been closed. This happens because the handle returned from CreateFile allows all
access (except WRITE_DAC when the inherited ACL from the containing folder contains
OWNER ACEs that deny WRITE_DAC), so the program can do whatever it needs to create the
file. The inherited ACL can be set to have an OWNER ACE that does not contain WRITE_DAC
and whatever other rights that it decided not to grant once the file is closed. However, if the
user could write code that directly sets an ACL at the time the file is created, it need not inherit
anything from the parent, so this measure isnt completely foolproof. This issue could also
apply to Active Directory objects.
Such a change does not affect TakeOwnership semanticsa user with SeTakeOwnership privilege will still be able to take ownership and acquire READ_CONTROL and WRITE_DAC rights.
When an administrator takes ownership of a file (which changes the owner SID), then the
DACL is examined for ACEs that contain the Owner SID. If an allow-Owner ACE is found,
then READ_CONTROL | WRITE_DAC are added to the access mask. If a deny-Owner ACE is
found, then READ_CONTROL | WRITE_DAC are removed from the mask.
Finally, this change does not affect quota either. Quota is charged to the owner of an object,
even if that owner does not have WRITE_DAC rights.

Call to Action

You should seriously consider using CardSpace in your Web-based application whether
its a Web site or a smart client using Web services. CardSpace helps mitigate one of the
most serious Internet crimes todayphishing. At the very least, you should use CardSpace as a user and then download the sample code and start experimenting.

If you built a GINA in the past, it will no longer work on Windows Vista, so it is important to understand the new Credential Provider model and replace your current code
with the new COM interfaces.

If youre using service-specific SIDs for your services resources, as we recommended in


Chapter 5, be sure to consider how youd like to handle owner rights when building your
access control lists.

References
(XMLSOAP 2002) WS-Security. http://schemas.xmlsoap.org/ws/2002/04/secext/. April 2002.
(XMLSOAP 2005a) Web Services Trust Language (WS-Trust). http://schemas.xmlsoap.org/

ws/2005/02/trust. February 2005.


(XMLSOAP 2006) Web Services Metadata Exchange (WS-MetadataExchange). http://

schemas.xmlsoap.org/ws/2004/09/mex/. August 2006.

162

Writing Secure Code for Windows Vista

Web Services Security Policy Language (WS-SecurityPolicy). http://


schemas.xmlsoap.org/ws/2005/07/securitypolicy/. July 2005.

(XMLSOAP 2005b)

(Microsoft 2006a) Microsoft Interoperatbility. Microsoft Open Specification Promise,

http://www.microsoft.com/interop/osp/default.mspx. October 2006.


(Cameron 2006)

Kim Camerons Identity Blog http://www.identityblog.com/.

(Microsoft 2006a) Windows CardSpace. http://cardspace.netfx3.com/.

Windows CardSpace Resources. http://msdn2.microsoft.com/en-us/


winfx/aa663320.aspx.

(Microsoft 2006b)

(Netcraft 2004) Netcraft Anti-Phishing Toolbar. http://toolbar.netcraft.com/.


(Channel9 2006) Microsoft Communities. Bertocci, Vittorio. WS-Trust Under the Hood,

http://channel9.msdn.com/Showpost.aspx?postid=241455. October 2006.


Vibro.NET Blog. Bertocci, Vittorio. http://blogs.msdn.com/vbertocci/archive/
tags/Windows+CardSpace/default.aspx.

(Bertocci 2006)

OASIS Security Services (SAML). http://www.oasis-open.org/committees/


tc_home.php?wg_abbrev=security.

(OASIS 2006)

Windows Vista Credential Providers. http://shellrevealed.com/files/


folders/code_samples/entry1019.aspx.

(Microsoft 2006c)

Microsoft Download Center. Windows Vista Credential Provider


Samples, http://www.microsoft.com/downloads/details.aspx?FamilyID=B1B3CBD12D3A-4FAC-982F-289F4F4B9300&displaylang=en. December 2006.

(Microsoft 2006d)

Chapter 9

Miscellaneous Defenses and


Security-Related Technologies
In this chapter:
Adding Parental Controls Support to Your Application . . . . . . . . . . . . . . . . . . . . .164
Windows Defender APIs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .167
New Credential User Interface API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .169
Use the Security Event Log. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .171
Pointer Encoding . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .172
Kernel Mode Debugging Issues. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .175
Programming the Trusted Platform Module (TPM) . . . . . . . . . . . . . . . . . . . . . . . . .175
Windows SideBar and Gadget Security Considerations. . . . . . . . . . . . . . . . . . . . . .181
References. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .182
This chapter outlines a number of security features and defenses in Windows Vista that do not
fit nicely into any of the previous chapters. The first subject is parental controls, a feature that
allows parents and guardians to define how children can use the computer. On the subject of
defending users, we also show how anti-malware vendors to can enable and disable Windows
Defender if needed. We then dive a little deeper and discuss important credential user interface changes, how to use the Windows security event log. Next, we dive very deep and show
how to protect long-lived pointers with pointer encoding; some kernel mode debugging
changes and wrap up with how to start thinking about the Trusted Platform Module support
in Windows Vista. Finally, we wrap up with some security best-practices when building
gadgets for the Windows SideBar.

Adding parental controls support to your application

Windows Defender APIs

New credential user interface API

Use the security event log

Pointer encoding

Kernel mode debugging issues

Programming the Trusted Platform Module (TPM)

Lets get started.


163

164

Writing Secure Code for Windows Vista

Adding Parental Controls Support to Your Application


Windows Vista provides Parental Controls (Microsoft 2006a) functionality to monitor and/or
limit exposure of selected computer users to inappropriate content. A parent or guardian can
restrict what Web sites children can visit, what games titles and games ratings they can use,
and what times the children are allowed to log on to the computer.
Parental Controls is available only in the consumer-focused versions of Windows Vista:

Windows Vista Starter Edition

Windows Vista Home Basic Edition

Windows Vista Home Premium Edition

Windows Vista Ultimate Edition

Tip

If you need to know on which version of Windows Vista your application is running,
you can call the new Windows Vista API GetProductInfo.

Also note that Parental Controls feature is not enabled by default for domain-joined computers, but you can enable it by following these steps:
1. Open MMC.exe.
2. Click File and then Add or Remove Snap-ins.
3. Double-click Group Policy Object Editor.
4. Click Finish and then click OK.
5. Expand the following nodes: Local Computer Policy, Computer Configuration,
Administrative Templates, Windows Components.
6. Click Parental Controls.
7. Double-click the Make Parental Controls control panel visible in a domain setting.
8. Click Enabled.
9. Click OK.
Another important point is that Parental Controls are only effective when the users under
Parental Control policy are not administrators.
Important

The Parent Controls feature is not 100 percent foolproof, and parents or
guardians should not abdicate the protection of their children to the Parental Controls
technology. Parents should make sure kids are aware of online dangers, and monitor the
Parental Controls activity reports regularly.

Chapter 9

Miscellaneous Defenses and Security-Related Technologies

165

The Code
To add Windows Parental Controls (WPC) functionality to your application, you must
include <wpc.h>, and because WPC is implemented as a COM object, there is no need to link
with a library.
You will find the following code at the start of all applications that support WPC:
CComPtr<IWindowsParentalControls> piWPC = NULL;
HRESULT hr = piWPC.CoCreateInstance(__uuidof(WindowsParentalControls));
if (SUCCEEDED(hr)) {
// cool!
}

Tip

As a general rule, we like to use the Abstract Type Library (ATL) when writing COM
code. ATL makes COM palatable.

Next, get the user settings; note the first argument to GetUserSettings can either be NULL to get
the settings for the current user, or a textual SID (of the S-1-5-21-xxx ilk) for a specific user.
Two functions, WpcuSidStringForCurrentUser and WpcuSidStringFromUserName in the
Windows Software Development Kit (Microsoft 2006b) sample code contained in a file
named Security\ParentalControls\Utilities\Utilities.cpp show how to create textual SIDs.
IWPCSettings* piWPCUserSettings = NULL;
hr = piWPC->GetUserSettings(pwszSid,&piWPCUserSettings);
if (E_ACCESSDENIED == hr) {
// user is probably an admin
} else if (SUCCEEDED(hr)){
// Cool!
}

Accessing user settings will fail with an E_ACCESSDENIED error when calling the IWPCSettings:: GetUserSettings method if the user is an administrator because parental controls do
not apply to administrators.

Time Limits
Windows Parental Controls includes time limits that allow a user access to the computer only
at predetermined times. If a users time is up, they are logged off and cannot log back on until
the time limit policy determined by the parent or guardian allows them to log back on. Use
the following code to determine if the user has time restrictions:
// Determine if time limits are in effect for this user
DWORD dwRestrictions = 0;
hr = piWPCUserSettings->GetRestrictions(&dwRestrictions);
if (SUCCEEDED(hr)) {
if (dwRestrictions & WPCFLAG_HOURS_RESTRICTED)
wprintf(L"Hour Restriction");
}

166

Writing Secure Code for Windows Vista

Fifteen minutes before a forced logoff, appropriately registered applications will receive a
WMI event. There is sample code in the Samples\Security\ParentalControls\ComplianceApp
folder of the Windows SDK that demonstrates how to register and handle these WMI events.
When the application receives this WMI event, your application should probably inform the
user that they will soon be logged off and had better save their work soon.

The 450 Error


Windows Parental Controls also supports Web restrictions and is TCP port agnostic. WPC
does not just monitor port 80, the technology monitors HTTP traffic at the WinSock layer to
determine whether the Web site should be blocked or allowed. Web blocking is not all or
nothing; a Web site could render correctly except for perhaps one JPG file that comes from a
blocked Web site.
WPC issues a 450 Blocked by Parental Controls error to browser and browser-like software
if it determines the site should be blocked, so your application might need to special-case the
450 error.

Detecting Whether Block file downloads Is Enabled


If your application is a Web browser, or has browser-like functionality, you should leverage the
Block file downloads option in WPC by using the following code to determine if file downloads are blocked or not.
DWORD dwRestrictions = 0;
hr = piWPCUserSettings->GetRestrictions(&dwRestrictions);
if (SUCCEEDED(hr)) {
if (dwRestrictions & WPCFLAG_WEB_SETTING_DOWNLOADSBLOCKED)
wprintf(L"Downloads restrictions\n");
}

Note that other restrictions include blocking certain games (WPCFLAG_GAMES_BLOCKED)


and applications (WPCFLAG_APPS_RESTRICTED).

Turning Off Filtering for Your Application or URL


Be careful here, but if you think WPC should not block requests by your application or certain
URLs should not be blocked, then you can use the WPC WMI interface to add your application or URLs to the dont block list:
try
{
const string property = @"HTTPExemptionList";
ManagementObject setting = new ManagementObject(
@"root\CIMV2\Applications\WindowsParentalControls",
"WpcSystemSettings=@",
new ObjectGetOptions( ));

Chapter 9

Miscellaneous Defenses and Security-Related Technologies

167

// get list of current exemptions


string[] exemptions = (string[])setting[property];
List<string> lst = new List<string>( );
lst.AddRange(exemptions);
// add our app to the list
lst.Add(@"c:\MyCode\myapp.exe");
exemptions = lst.GetRange(0, lst.Count).ToArray( );
// save the updated exemption list
setting[property] = exemptions;
setting.Put( );
}
catch (ManagementException e)
{
// This is a version of Windows Vista that does not have
// Parental Controls, or you are not an admin
System.Console.WriteLine(e.ToString( ));
}

Note that this code must run with full administrator privileges to add an exemption. Also note
the WMI object used is unfortunately named HTTPExemptionList; take our word for it that this
is the object that holds a list of exempted applications! If you want to add a URL to the list,
then use the URLExemptionList object. If you look at the WPC WMI schema, youll notice two
other similarly named classes: WinHTTPExemptionList and WinURLExemptionList. These are
read-only lists of exemptions that apply to all users.

Logging Events
Microsoft cannot make computers safer to use online alone; we need the help of Independent
Software Vendors (ISVs) too. One way you can help is by logging interesting online events in
the WPC activity reports. For example, if you build some form of instant messaging system,
you should log the time and date of the communication, as well as the IP address or DNS
name of the remote computer. David Bennett of the Parental Controls team at Microsoft has a
good logging code sample on his blog (Bennett 2006).

Windows Defender APIs


Windows Vista includes Windows Defender to help detect and remove certain kinds of potentially unwanted software, such as spyware. It is not a replacement for a full-featured anti-virus
package, however. If you are an ISV that builds an anti-malware tool, you may want to disable
Windows Defender programmatically. To protect users, you should only disable Windows
Defender after:
1. You have successfully turned on your anti-spyware solution with the recommended
settings and
2. You have notified the user that Windows Defender is going to be disabled.

168

Writing Secure Code for Windows Vista

Windows Vista exposes two functions to enable and disable Windows Defender and another
to determine the current status of Windows Defender. Only administrators can enable or disable Windows Defender.
The following code detects if Windows Defender is disabled and if it is, turns it on.
typedef HRESULT (WINAPI *WDSTATUS)(BOOL*);
typedef HRESULT (WINAPI *WDENABLE)(BOOL);
// Get the path to Program Files, it might be localized
wchar_t wszPath[MAX_PATH];
HRESULT hr = SHGetFolderPathAndSubDir(
NULL,
CSIDL_PROGRAM_FILES,
NULL,
SHGFP_TYPE_CURRENT,
L"Windows Defender",
wszPath);
if (FAILED(hr))
return hr;
wcscat_s(wszPath, MAX_PATH, L"\\MpClient.dll");
HMODULE h = LoadLibrary(wszPath);
if (!h) {
DWORD dwErr = GetLastError();
return dwErr;
}
WDSTATUS pfnWDStatus = (WDSTATUS)GetProcAddress(h,"WDStatus");
WDENABLE pfnWDEnable = (WDENABLE)GetProcAddress(h,"WDEnable");
if (pfnWDStatus && pfnWDEnable) {
BOOL fEnabled = FALSE;
HRESULT hr = pfnWDStatus(&fEnabled);
if (SUCCEEDED(hr)) {
if (fEnabled) {
wprintf(L"Windows Defender is already enabled.");
} else {
hr = pfnWDEnable(TRUE);
if (SUCCEEDED(hr)) {
wprintf(L"Windows Defender is now enabled.");
} else {
wprintf(L"Could not enable Windows Defender, err = %X.",hr);
}
}
}
}
FreeLibrary(h);

Read the Windows Defender Policy Documentation!


As soon as possible, you should read two very important Windows Defender policy documents, Windows Defender Antispyware Cycle (Microsoft 2006c) and How Windows
Defender Identifies Spyware (Microsoft 2006d).

Chapter 9

Miscellaneous Defenses and Security-Related Technologies

169

Sign Your Code


We have already discussed how important signing your code is to provide users a smoother
UAC experience, but signing software also has a less obvious benefit in that it allows an analyst at Microsoft to speed the analysis process, resulting in a shorter time period where new
software is listed as Not Yet Classified in Windows Defender's Software Explorer. Windows
Defender is designed to provide visibility and control to the individual as to what is allowed
to run on his or her computer. To do this, the Microsoft Security Research & Response team
must analyze and rate software based on the specific behaviors of the software. In cases
where the behaviors go against the objective criteria described at the Windows Defender
Web site (Microsoft 2006d) that software will generate an alert. In the case where the
analysis shows the software is free of potentially unwanted behaviors, it can be marked as
known, thereby suppressing alerts. In cases where the software has not yet been analyzed, it
will appear in Windows Defenders Software Explorer (and potentially in events in the event
log) as Not Yet Classified, which is discussed next.

Request to Be Added to the Windows Defender


Known or Not Yet Classified Lists
Microsoft does not accept submissions from vendors or individuals for inclusion of a specific
piece of software in the Known list. Programs are considered for addition to the Known
list based on input from users through SpyNet, the opt-in telemetry system used by Windows
Defender. A high threshold of Windows Defender users must have reported the program to
SpyNet, and a significant majority of those users must have elected to Allow the program to
run on their computer. After these criteria have been met, Microsofts research team then
reviews this list of candidates to confirm that these programs are not known to have issues
with potentially unwanted behavior and are not currently under investigation.
Programs listed as Known are commonly used and allowed by SpyNet participants and do
not appear to have issues with potentially unwanted behavior. Programs raised as Unknown
to the user are less commonly used and/or allowed among SpyNet participants. It is important to note that programs marked Unknown are not necessarily spyware or other forms of
potentially unwanted software. These programs are raised to the user's attention so that they
can make an informed decision about what runs on their computer. To help minimize the possibility of confusion, alerts relating to software that is Not Yet Classified are suppressed by
default but will appear in the Event Log and in Windows Defender Software Explorer.

New Credential User Interface API


Windows Vista includes a new function to prompt for user credentials, CredUIPromptForWindowsCredentials. Rather than using CredUIPromptForCredentials, you should use the new
function because the credential is encrypted by the operating system and can be unpacked by
the application when needed without the application having access to the encryption key.

170

Writing Secure Code for Windows Vista

In short, credentials are always encrypted until needed. The following code is an example of
how to use the API:
CREDUI_INFO ci = {0};
ULONG
ulAuthPkg = 0;
void
*pAuthBuff = NULL;
ULONG
cbAuthBuff = 0;
void
*pOutAuthBuff = NULL;
ULONG
cbOutAuthBuff = 0;
BOOL
fSave = FALSE;
DWORD
dwFlags = CREDUIWIN_CHECKBOX;
ci.cbSize = sizeof ci;
ci.hbmBanner = NULL;
ci.hwndParent = NULL;
ci.pszCaptionText = L"Writing Secure Code for Windows Vista";
ci.pszMessageText = L"Please enter your password";
DWORD dwErr = CredUIPromptForWindowsCredentials(
&ci,
0,
&ulAuthPkg,
pAuthBuff,
cbAuthBuff,
&pOutAuthBuff,
&cbOutAuthBuff,
&fSave,
dwFlags);
if (dwErr != 0) {
wprintf(L"CredUI failed, err = %d\n",dwErr);
return dwErr;
}
WCHAR
DWORD
WCHAR
DWORD
WCHAR
DWORD

wszUsername[CREDUI_MAX_USERNAME_LENGTH + 1];
cchUsername = _countof(wszUsername);
wszPassword[CREDUI_MAX_PASSWORD_LENGTH + 1];
cchPassword = _countof(wszPassword);
wszDomain[CRED_MAX_DOMAIN_TARGET_NAME_LENGTH + 1];
cchDomain = 0;

// Attempt to decrypt the users password


BOOL fOK = CredUnPackAuthenticationBuffer(
CRED_PACK_PROTECTED_CREDENTIALS,
pOutAuthBuff,
cbOutAuthBuff,
wszUsername,
&cchUsername,
wszDomain,
&cchDomain,
wszPassword,
&cchPassword);
if (!fOK) {
wprintf(L"Unpack failed, err = %d\n",GetLastError());
} else {

Chapter 9

Miscellaneous Defenses and Security-Related Technologies

171

// Use the creds


SecureZeroMemory(wszPassword);
}
if (pOutAuthBuff) {
SecureZeroMemory(pOutAuthBuff,cbOutAuthBuff);
CoTaskMemFree(pOutAuthBuff);
pOutAuthBuff = NULL;
}

The most important reason to use this function over the older credential user interface API is
the ability to display the credential dialog on the Windows logon desktop, therefore reducing
the chance an attacker can spoof the dialog and steal a users credentials. You can enable this
setting in Group Policy by navigating to Computer Configuration | Administrative Templates |
Windows Components | Credential User Interface, and then enable Require trusted path for credential entry. From now on, when an application calls CredUIPromptForWindowsCredentials
she will see the series of dialogs shown in Figures 9-1 and 9-2.

Figure 9-1

First stage of CredUI prompting for user credentials on the Windows logon desktop.

Figure 9-2

Second stage of CredUI prompting for user credentials on the Windows logon desktop.

Once the user presses Ctrl-Alt-Del, the credential dialog appears on the Windows logon desktop.

Use the Security Event Log


Seriously consider writing security-related events, such as those in the following list, to the
Windows security event log rather than writing to your own log file.

Result of a security decision (some action was allowed or denied)

Change in a policy or setting that might affect the outcome of security decisions (including old and new value of a security setting)

172

Writing Secure Code for Windows Vista

Change in state that might affect the outcome of security decisions (load module, start
module, stop module, etc.)

Management of application-specific user accounts (create, delete, manage groups,


change password, enable, etc.)

Application authentication (user logged in/disconnected)

Application-specific suspicious behavior or integrity violation (this is application specific, but for example, if a Web application detects an SQL injection attempt, it might
choose to log that, or an anti-virus program might log that it detected a virus, etc.)

Microsoft added a new API, AuthzReportSecurityEvent, to Windows Server 2003 and Windows
Vista to log such data easily. The Windows security log is Common Criteria compliant at EAL4+;
and although this doesnt guarantee Common Criteria compliance for your application, it may
reduce the amount of work required to achieve Common Criteria for your application.
Windows authentication, authorization, and account management functions all generate
appropriate audit trails in the Windows security event log. If you use these functions of Windows rather than implement your own, then auditing will be done for you. One final point,
dont flood logs with irrelevant information, just log critical data that could help administrators.

Pointer Encoding
Pointer encoding is neither an SDL requirement nor a Windows Vista security quality gate
requirement, but we worked very closely with Windows Vista developers to make sure they
were educated about the value of pointer encoding. Many long-lived pointers in Windows
Vista are encoded to help protect them from becoming buffer-overrun victims.
Technically, pointer encoding isnt a code quality benefit; its a defensive measure only. Its very
common to use pointers in C and C++. In fact, one of the major benefits of C and C++ is that the
languages expose pointers to arbitrary memory locations and code can read from and write to
arbitrary computer memory. Accessing memory directly is a double-edged sword: its powerful,
but failure can be catastrophic because this can be a source of buffer-overrun vulnerabilities.
Introduced in Windows Server 2003 SP1 and Windows XP SP2, pointer encoding allows
developers to make it harder for an attacker to successfully overwrite a pointer with a valid
value. Take a look at the following contrived code:
class Stuff {
public:
Stuff( ) {
m_dest = new char[32];
m_data = new char[1];
}
~Stuff() {
delete [] m_dest;
delete [] m_data;

Chapter 9

Miscellaneous Defenses and Security-Related Technologies

173

}
const char *WriteData(const char *src) {
if (!src) return NULL;
if (m_dest) strcpy(m_dest,src);
if (m_data) *m_data = src[0];
return src;
}
private:
char *m_dest, *m_data;
};

Assuming the attacker controls src when calling the WriteData method, she can overflow
m_dest, and in doing so overwrite the m_data pointer (because its a few bytes higher in memory) with whatever value she wants. Because the attacker controls src, and therefore m_dest,
and because the vulnerable code calls strcpy and overflows m_dest, she controls m_data. The
code then writes the first byte of src to m_data, and now the attacker can very effectively write
one byte anywhere in memory. This is a classic heap-based buffer overrun (see Figure 9-3). Of
course, the code is bad because it uses strcpy, which is banned as we pointed out in Chapter 1,
Code Quality.
m_dest

m_data
src overflows the first buffer,
corrupting the second

src

Heap-based buffers

Figure 9-3

Overflowing a heap-based buffer to corrupt another buffer.

Now take a look at the same contrived C++ class code using pointer encoding.
class Stuff {
public:
Stuff() {
m_dest = (char*)EncodePointer(new char[32]);
m_data = (char*)EncodePointer(new char[1]);
}
~Stuff() {
delete [] DecodePointer(m_dest);
delete [] DecodePointer(m_data);
m_data = m_dest = NULL;
}
const char *WriteData(const char *src) {
if (!src) return NULL;
char *dest = (char*)DecodePointer(m_dest);
if (dest) strcpy(dest,src);
char *data = (char*)DecodePointer(m_data);
if (data) *data = src[0];
return src;
}

174

Writing Secure Code for Windows Vista


private:
char *m_dest, *m_data;
};

This code is very similar to the original code, except that the pointers are deemed long-lived
and are encoded as soon as they are created and then decoded prior to use. You will also
notice that the class destructor sets the pointers to NULL after the memory is deleted; Im in
the habit of setting freed pointers to NULL; it can help mitigate exploitable double-free bugs
as described in Chapter 3, Buffer Overrun Defenses.
Follow these steps when dealing with long-lived pointers:
1. Allocate memory or initialize the pointer, and assign the pointer to the address.
2. Encode the pointer.
3. In the line above the code where the pointer is used, decode the pointer into a temporary
variable.
4. When the pointer is no longer needed, decode the pointer and free it.
5. Set the pointer to NULL.
Note that DecodePointer wont fail; it will just give you back a bad pointer. If youd like to make
this really safe, wrap this in a class and keep a reference copy of the pointer. Heres an
example:
class EncodedPointer {
public:
EncodedPointer() : m_pv( NULL ), m_pReference( NULL ){}
void Set( void* pIn ) {
m_pv = EncodePointer( pIn );
m_pReference = MakeRefPtr( pIn );
}
void* Get() {
if( m_pv == NULL )
return NULL;
void* pRet = DecodePointer( m_pv );
// Now double-check for tampering
if( MakeRefPtr( pRet ) != m_pReference )
return NULL;
return pRet;
}
#ifdef _DEBUG
// testing only
void Corrupt() {
m_pv = (void*)((char*)m_pv + 1);
}
#endif
private:
void* MakeRefPtr( void* pIn ){

Chapter 9

Miscellaneous Defenses and Security-Related Technologies

175

return reinterpret_cast< void* >(


reinterpret_cast< size_t >( pIn ) ^
reinterpret_cast< size_t >( this ) );
}
void* m_pv;
void* m_pReference;
};

The following code shows how to use this simple class:


char buf[2];
EncodedPointer ePtr;
ePtr.Set( buf );
if( ePtr.Get() == NULL )
printf("Ptr is corrupt or NULL\n");
else
printf("Valid!\n");

Before you use this class a great deal, remember that you ought to do some work to implement
the copy constructor and assignment operator. If you assigned one of these classes to another
instance of the class, it would be invalid because the C++ this pointer changes. What the class
does is to make it very unlikely that a corrupted pointer would get returned as anything other
than NULL, and dereferencing a null pointer wont typically be exploitable. This also gives
you a way to check for success or failure, or even throw an exception if it does fail.

Kernel Mode Debugging Issues


By default, local and remote kernel mode debugging is only possible on Windows Vista when
the system is booted with debugging explicitly enabled. You can enable kernel mode debugging with the following command from an elevated command prompt:
bcdedit -debug on

You can disable kernel mode debugging by issuing the following:


bcdedit -debug off

or
bcdedit -deletevalue debug

The change does not take effect until the next system reboot.

Programming the Trusted Platform Module (TPM)


The Trusted Platform Module (TPM) is the product of a specification from the Trusted Computing Group (TCG 2006a), designed to enhance system security by moving many sensitive

176

Writing Secure Code for Windows Vista

cryptographic operations into hardware. Windows Vista supports TPM 1.2. The most wellknown feature that uses the TPM, if one is available, is BitLocker Drive Encryption and its
secure start-up capability (Microsoft 2006e).
Tip

BitLocker can be used without a TPM, but it only offers drive encryption, not secure
start-up.

What Is a Trusted Platform Module?


There are numerous security technologiesin the form of software and internal and
external hardwarethat provide some form of trust for the applications. There is, however, general consensus that software-based roots of trust are significantly less resilient
than hardware-based solutions. For widespread industry adoption that balances reasonable cost and a quality user experience an integrated hardware solution that is a part of
the motherboard and that has anti-tampering characteristics is ideal. A standardized
implementation is, clearly, very important.
There are significant software product and service opportunities that require such
hardware-based security, but without being able to depend on either general presence or
an adoptable standard, these features will either not be created at all or insecure software
alternatives will be used with limited acceptance.
The Trusted Computing Group is a non-profit organization that was formed to develop,
define, and help promote an open standard for a hardware-based root of trust that
allowed for innovation, and it has met most if not all of the needs detailed earlier. Their
most well-known result is the specification describing the TPM 1.2 chip.
At the highest level, the TPM is a microcontroller that stores keys, cryptographic hashes,
and digital certificates. It can provide a unique public and private key pair, verify data
integrity, and release keys dependent on an unchanged environmental state as well as
offering other cryptographic services. Strong keys and secure decision making are fundamental to all security features. The TPM is the only standard hardware of its kind that
is attachable to the motherboard.
As it stands in Windows Vista, the TPM is not exposed in a general-purpose fashion that can
be used to take full advantage of the capabilities the TPM provides. Using the TPMs ability to
create and store cryptographic keys or perform cryptographic operations requires additional
development effort.
Tip

You can only successfully call TPM functionality from elevated processes.

Chapter 9

Miscellaneous Defenses and Security-Related Technologies

177

What is exposed today in Windows Vista are WMI interfaces (Microsoft 2006f) to build
TPM and BitLocker management tools. The following C# code shows how to query a TPM
using WMI:
using System.Management;
static private ManagementObject m_wmiObject = null;
static Boolean BooleanMethod(String method)
{
ManagementBaseObject outParams = m_wmiObject.InvokeMethod(method, null, null);
return (0 == (UInt32)outParams["ReturnValue"]) ? false : true;
}
static void Main(string[] args)
{
try
{
string tpm = "root\\cimv2\\security\\microsofttpm:Win32_Tpm=@";
m_wmiObject = new ManagementObject(tpm);
String version = m_wmiObject.GetPropertyValue("SpecVersion").ToString();
Boolean fEnabled = BooleanMethod("IsEnabled");
UInt32 id = (UInt32)m_wmiObject.GetPropertyValue("ManufacturerId");
}
catch (ManagementException me)
{
Console.WriteLine(me.Message);
}
}

Here is something similar, but using VBScript:


Set objWMIServices = GetObject("winmgmts:\\.\root\cimv2\Security\MicrosoftTpm")
Set objWMIInstance = objWMIServices.Get("Win32_Tpm=@")
If Err.Number<>0 Then
WScript.Echo "Cannot find a TPM in this PC."
Wscript.Quit
End If
WScript.Echo "TPM Found"
WScript.Echo "TPM Enabled: " + CStr(objWMIInstance.IsEnabled)
WScript.Echo "TPM Owned : " + CStr(objWMIInstance.IsOwned)

These WMI providers sit atop the Windows Vista TPM Base Services (TBS), which runs as a
system service and exposes a small number of APIs (Microsoft 2006g) to software developers
wanting to build TPM-aware applications.

Low-Level Access to the TPM


You can program directly to the TPM using the TBS APIs, or you can use a vendor-provided
TCG Software Stack (TSS) (TCG 2006b) to make development easier. The TSS is an
abstraction layer that makes writing to the TPM much simpler. The TBS in Windows Vista
behaves like an old-school driver, and code written this way can be complicated and very

178

Writing Secure Code for Windows Vista

time-consuming, as you will see in the next code sample. A TSS package helps by reducing the
complexity of TPM commands and provides a much simpler API for a TPM application developer to use.
The following C++ example shows how to write to the TBS directly. This sample code gets the
TPM version information and 32 random bytes.
// returned data starts at byte 10
#define TPM_DATA_OFFSET 10
#ifdef _DEBUG
// Display TPM data hex dump
void TpmDisplayRawResult(
__in_bcount(cbResult) BYTE *pbResult,
UINT32 cbResult) {
if (!cbResult || !pbResult)
return;
if (cbResult >= TPM_DATA_OFFSET) {
wprintf(L"Tag : %02X %02X\n",
pbResult[0], pbResult[1]);
wprintf(L"Len : %02X %02X %02X %02X\n",
pbResult[2], pbResult[3], pbResult[4], pbResult[5]);
wprintf(L"Err : %02X %02X %02X %02X\n",
pbResult[6], pbResult[7], pbResult[8], pbResult[9]);
if (cbResult > TPM_DATA_OFFSET) {
wprintf(L"Data: ");
for (UINT32 i=TPM_DATA_OFFSET; i < cbResult-TPM_DATA_OFFSET; i++)
wprintf(L"%02X ",pbResult[i]);
wprintf(L"\n");
}
}
}
#endif
#define MAX_RNG_BUFF 64
#define TPM_RNG_OFFSET 14
HRESULT TpmGetRandomData(
TBS_HCONTEXT hContext,
__inout_bcount(cData) BYTE *pData,
UINT32 cData) {
if (!hContext || !pData || !cData || cData > MAX_RNG_BUFF)
return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
BYTE bCmd[] = {0x00, 0xc1,
// TPM_TAG_RQU_COMMAND
0x00, 0x00, 0x00, 0x0e,
// blob length in bytes
0x00, 0x00, 0x00, 0x46,
// TPM API code (TPM_ORD_GetRandom)
0x00, 0x00, 0x00, (BYTE)cData};// # bytes
UINT32 cbCmd = sizeof bCmd;
BYTE bResult[128] = {0};
UINT32 cbResult = sizeof bResult;
HRESULT hr = Tbsip_Submit_Command(hContext,
TBS_COMMAND_LOCALITY_ZERO,
TBS_COMMAND_PRIORITY_NORMAL,

Chapter 9

Miscellaneous Defenses and Security-Related Technologies

bCmd,
cbCmd,
bResult,
&cbResult);
#ifdef _DEBUG
if (FAILED(hr))
wprintf(L"Tbsip_Submit_Command failed %X",hr);
else
TpmDisplayRawResult(bResult,cbResult);
#endif
if (SUCCEEDED(hr))
memcpy(pData,TPM_RNG_OFFSET+bResult,cData);
return hr;
}
HRESULT TpmGetVersion(
TBS_HCONTEXT hContext,
__in_ecount(cVersion) wchar_t *wszVersion,
UINT32 cVersion) {
if (!hContext || !wszVersion || !cVersion)
return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
BYTE bCmd[] = {0x00, 0xc1, // TPM_TAG_RQU_COMMAND
0x00, 0x00, 0x00, 0x12, // blob length in bytes
0x00, 0x00, 0x00, 0x65, // TPM API code (TPM_ORD_GetCapability)
0x00, 0x00, 0x00, 0x06, // TCPA_CAP_VERSION
0x00, 0x00, 0x00, 0x00};// no sub capability
UINT32 cbCmd = sizeof bCmd;
BYTE bResult[128] = {0};
UINT32 cbResult = sizeof bResult;
HRESULT hr = Tbsip_Submit_Command(hContext
TBS_COMMAND_LOCALITY_ZERO,
TBS_COMMAND_PRIORITY_NORMAL,
bCmd,
cbCmd,
bResult,
&cbResult);
#ifdef _DEBUG
if (FAILED(hr))
wprintf(L"Tbsip_Submit_Command failed %X",hr);
else
TpmDisplayRawResult(bResult,cbResult);
#endif
if (SUCCEEDED(hr))
swprintf_s(wszVersion,cVersion,L"TCG v%d.%d, Firmware v%d.%d",
(UINT32)bResult[14],
(UINT32)bResult[15],
(UINT32)bResult[16],
(UINT32)bResult[17]);
return hr;
}
int main(int argc, char* argv[]) {

179

180

Writing Secure Code for Windows Vista


argv;
argc;
// Create a TBS context
TBS_HCONTEXT hContext = 0;
TBS_CONTEXT_PARAMS contextParams = {0};
contextParams.version = TBS_CONTEXT_VERSION_ONE;
HRESULT hr = Tbsi_Context_Create(&contextParams, &hContext);
if (FAILED(hr))
return hr;
wchar_t wszVersion[32];
if (SUCCEEDED(TpmGetVersion(hContext,wszVersion,_countof(wszVersion))))
wprintf(L"%s\n",wszVersion);
BYTE buff[64];
UINT32 cBuff = sizeof buff;
if (SUCCEEDED(TpmGetRandomData(hContext,buff,cBuff)))
for (UINT32 i=0; i < cBuff; i++)
wprintf(L"%02X ",buff[i]);
if (hContext)
Tbsip_Context_Close(hContext);
return 0;
}

When calling into the TBS, you must set up an input buffer that contains function arguments,
pass that to the Tbsip_Submit_Command function, and then query the response buffer for status and results.
Note

TBS functions that start with Tbsip result in a direct TPM call, and functions that start
with Tbsi do not directly call the TPM.

The format of the input buffer is shown in Table 9-1.


Table 9-1

The TPM Input Buffer Format

Data Size (bytes) TPM Type

Comment

TPM_TAG

Packet type (e.g., a request,


TPM_TAG_RQU_COMMAND, 0xC1)

UINT32

Total packet length in bytes

TPM_CMD_CODE

TPM command code (e.g., TPM_ORD_GetCapability,


0x65 or TPM_ORD_GetRandom, 0x46)

Variable

Often BYTE[] or UINT32 Arguments for the command

The format of the output buffer is shown in Table 9-2.


Table 9-2

The TPM Output Buffer Format

Data Size (bytes) TPM Type

Comment

TPM_TAG

Packet type (e.g., a response, TPM_TAG_RSP_COMMAND, 0xC4)

UINT32

Total packet length in bytes

Chapter 9

Miscellaneous Defenses and Security-Related Technologies

181

Table 9-2 The TPM Output Buffer Format


Data Size (bytes) TPM Type

Comment

TPM_RESULT

Error value.

Variable

Often BYTE[]
or UINT32

Returned data from command.

The sample code shown earlier issues a TPM command to get TPM chip version information.
To learn more about the different TPM commands and the in and out buffers, you should refer
to the TCG documentation (TCG 2006c).
To summarize this TPM material, most software developers will not need to write any TPMaware software because its very specialized; for those who need to create TPM-aware applications, though, you can use high-level WMI interfaces, a TCG Software Stack (TSS) ported to
work with the TBS, or the low-level TPM Base Service function calls in Windows Vista.

Windows SideBar and Gadget Security Considerations


The Windows SideBar is a process that hosts small applications called gadgets written in
HTML and JavaScript. You should treat gadgets as fully trusted code that run in the same
security context as the user. When writing a gadget be aware that they can be subject to
cross-site scripting bugs (Howard, LeBlanc, Viega 2005) if the gadget does not sanitize
untrusted input correctly. You should adhere to the following best practices if your gadget
renders untrusted data.
Most importantly, verify the data is correctly formatted using a regular expression and don't
look solely for bad input characters, rather look for what you expect the input to be.
Set the gadget's HTML pages to use a predefined and appropriate codepage such as the
following:
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">

As a defense-in-depth mechanism, encode all untrusted data with code such as the following
sample, which will perform HTML encoding and neuter any script.
function sanitizeHTML(s) {
s = s.replace(/'/g,"&apos;");
s = s.replace(/"/g,"&quot;");
var d = document.createElement('div');
d.appendChild(document.createTextNode(s));
return d.innerHTML;
}

You should always enclose untrusted data in quotes when used as an attribute's value. Also
validate untrusted data used as URL values beginning with a supported protocol like http://,
https://, etc. (This will prevent attacks where a URL allows script, such as <A HREF=
javascript:alert(document.cookie)>Link1</A>

182

Writing Secure Code for Windows Vista

References
Windows Vista Parental Controls. http://www.microsoft.com/windows/
products/windowsvista/features/details/parentalcontrols.mspx.

(Microsoft 2006a)

Windows Software Development Kit. Script in Feeds, http://


blogs.msdn.com/rssteam/archive/2006/08/07/691248.aspx. Microsoft Team RSS Blog,
August 2006.

(Microsoft 2006b)

Bennett, David. How to Log a Crimson Event to the Custom Log (for
Parental Controls), http://blogs.technet.com/david_bennett/archive/2006/08/28/
452296.aspx. August 2006.

(Bennett 2006)

Windows Defender Antispyware Cycle, http://www.microsoft.com/


athome/security/spyware/software/msft/antispywarecycle.mspx. October 2006.

(Microsoft 2006c)

(Microsoft 2006d) How Windows Defender Identifies Spyware, http://www.microsoft.com/

athome/security/spyware/software/msft/analysis.mspx. October 2006.


(TCG 2006a)

Trusted Computing Group. https://www.trustedcomputinggroup.org/home.

Windows Hardware Developer Central. BitLocker Drive Encryption


Frequently Asked Questions, http://www.microsoft.com/whdc/system/platform/
hwsecurity/BitLockerFAQ.mspx. May 2006.

(Microsoft 2006e)

Security WMI Providers Reference, http://msdn2.microsoft.com/en-us/


library/aa376476.aspx.

(Microsoft 2006f)

Trusted Platform Module (TPM) Base Services, http://


msdn2.microsoft.com/en-us/library/aa446796.aspx.

(Microsoft 2006g)

(TCG 2006b) Trusted Computing Group. TPM Software Stack (TSS) Specifications,

https://www.trustedcomputinggroup.org/specs/TSS.
Trusted Computing Group. Trusted Platform Module (TPM) Specifications,
https://www.trustedcomputinggroup.org/specs/TPM.

(TCG 2006c)

Howard, Michael, David LeBlanc and John Viega.


19 Deadly Sins of Software Security, Emeryville, CA: McGraw-Hill, 2005.

(Howard, LeBlanc, Viega 2005)

Howard_Index.fm Page 183 Saturday, March 10, 2007 3:01 PM

Index
Symbols and Numbers
*p, 6
**p, 6
4-byte overwrites, and exception handling, 7172
40- and 56-bit ciphers, 133
64-bit code, and exception handling, 72
256-bit AES, 133
450 error, 166

A
Abstract Type Library (ATL), COM code and, 165
access checking, disabling, 104
access control, 1314, 107110
Access Control Entries (ACEs), 1920
Owner Rights, 160
access control lists (ACLs), 14, 17
DACLs, 32, 160
namespaces, global and local, 111
service accounts, 99102
shared memory, 112
Active Directory, owner SIDs, 160161
Active Type Library (ATL), and DEP, 127
ActiveX opt-in, 122123
locking, 131132
address space, 76
Address Space Layout Randomization (ASLR),
5153
limitations of, 53
link with /dynamicbase, 72
performance and capability implications, 5354
addresses, application, and stack randomization, 54
AdjustTokenPrivileges, 16, 102104
administrator user accounts, 1314
administrator with approval mode, 1820
applications requiring, building, 2224
elevated code, starting, 27
elevating to, 24
local system service accounts, 99
Adobe Acrobat Reader v8.0.0, 128
Adobe Flash, 121, 122
Adobe Flash Player v9.0.28.0, 128
Advanced Encryption Standard (AES), 132133
Advanced Windows (Richter), 67
Advanced Windows Firewall, 8792
AES-256 encryption key, 154
AIA (Authority Information Access) URLs, 146
algorithms
CNG, elliptic curve, 140
CNG, new, 139140
cryptographic, 9

hash, 9
hardcoded, 137, 148
Suite B, 144
allocation attack patterns, 5556
AMD CPUs, 11
Enhanced Virus Protection, 59
analysis tools, 9
/analyze, 5, 7, 9
warnings, 10
annotation, of functions, 3
anti-malware, 167168
anti-virus protection, 167168
APIs (application programming interfaces)
ASLR and, 51
AuthzReportSecurityEvent, 172
banned. See APIs, banned
CertEnroll, 148
ChangeServiceConfig2, 103
CreateService, 98
credential user interface, 163
GetProductInfo, 164
impersonation, 17
IP Helper, 76
kernel mode, 136
Network Diagnostics
Framework, 75
Network List Manager (NLM), 75, 8182
peer-to-peer collaboration, 75
pipe server attacks, 115116
secure socket extensions, 76, 8385
TBS, 177
user-mode, 136
Windows Defender, 163, 167168
APIs, banned, 3
bug prevention, 2
list of, 89
not replaced, 8
removing from codebase, 89
Application Compatibility toolset, 31
application manifest, side-by-side, creating, 31
application programming interfaces (APIs). See APIs
(application programming interfaces)
Application Verifier (AppVerif), 9
warnings, 11
applications
accessibility, 24
administrator-only, creating, 2224
compatibility of, debugging, 4244
high- vs. low-priority, 24
legacy, 28

183

Howard_Index.fm Page 184 Saturday, March 10, 2007 3:01 PM

184

AppPath
prompt for credentials or consent, creating, 2425
virtualization and, 28
AppPath, 109
asInvoker manifest option, 23, 24
ASLR. See Address Space Layout Randomization
(ASLR)
assertions, 156
assumption flaws, 3
ATL (Abstract Type Library), COM code and, 165
attacks
allocation, 5556
denial of service, 115117
malware, 60, 121, 154
name squatting, 110
phishing, 152, 153156
pipe server, 115116
screen-scraping, 158
shatter, 24, 110
spoofing, 158, 171
spyware, 167168
Web browser, 121122
attribute syntax, 3
auditing, 143, 172
authentication and authorization, 117, 151
authentication modules, 159
CardSpace and Information Cards, 151159
Graphical Identification and Authorization (GINA),
159
owner SID, 159161
Authenticode signatures, 44
Authority Information Access (AIA) URLs, 146
AuthzReportSecurityEvent, 172
Background Intelligent Transfer Service (BITS), 75

B
Backup Operators user group, 21
backward compatibility, 9
bank, online, phishing example, 154156
base functions, banned, 8
base process priority, changing, 107
BaseNamedObjects, 101
bcount, 5
BCrypt* functions, 136
BCryptAddContextFunctionProvider, 137138
BCryptCreateHash, 141
BCryptDeriveKey, 144
bcrypt.dll, 140
BCryptGetFipsAlgorithmMode, 143
<bcrypt.h>, 140
BCryptOpenAlgorithmProvider, 141
Bell-Lapadula integrity model, 40
benign privileges, 106107
Bennett, David, 167
Biba integrity model, 40

big-endian format, 6
binary patching, 8
BIOS options, and NX, 6162
BitLocker Drive Encryption, 176177
BITS (Background Intelligent Transfer Service), 75
blocking, 166. See also parental controls
bool, 9394
BOOL, 9394
Boolean arguments, 27, 9394
buffer overrun, 4, 8. See also buffer overrun defenses
warnings, 10
buffer overrun defenses, 4950
ASLR, 5154
DEP, 59, 62, 126129
/GS, 6467
heap defenses, 5559, 173
NX, 5964
pointer encoding, 172
safeSEH, 6772
stack randomization, 5455
buffers, 34, 7
functions and, 57
input, TPM, 180
output, TPM, 180181
source, 8
stack, 50
string, SAL annotation and, 38
bugs, 1
banned API removal and, 2
double-free, 57
privilege, 15
requestedPrivileges, Windows XP, 23
SAL annotation and, 2
static analysis, 911
Unknown SID type, Windows Vista, 34
Bugs or Defects? (Humphrey), 50
Button_SetElevationRequiredState macro, 27
Bypassing Windows Hardware-Enforced Data
Execution Prevention (Skape and
Skywing), 60
BYTE*, 6
bytes, counting, 8

C
C/C++
banned APIs, 2, 89
compiler and linkage options, 11
exception handling, 6768
heap defense functions, 57
pointers, 34, 172, 173175
SAL annotation, 2, 38
service writing in, 96
static analysis, 910
string buffers, 3
token access, 1516

Howard_Index.fm Page 185 Saturday, March 10, 2007 3:01 PM

ConvertStringSidToSid
TPM writing, 178180
unmanaged, 3, 11
C runtime (CRT) functions, 3
C runtime headers, 8
C runtime library, and ASLR, 52
C# programming
credential/consent prompts, 25
TPM queries, 177
C4966 warning, 8
C6387 warning, 7
calc.exe, 129
cacls tool, 101
callbacks, 117
callees (implementations), 3
callers (clients), 3
Cameron, Kim, 159
canonicalization functions, 130131
CAPICOM, 148, 157
CardSpace. See Windows CardSpace and
Information Cards
cbcount, 8
cchcount, 8
CDP (Certificate Revocation List Distribution
Point), 145
CertEnroll, 148
CertGetCertificateChain, 146147, 148
certificate common name (CN), 155
certificate events, viewing, 147
Certificate Revocation List (CRL) revocation checks,
145147
Certificate Revocation List
Distribution Point (CDP), 145
certificate verification, 145146
server, 153
SSL/TLS, 155
certificates, root, 148
certutil url tool, 147
ChangeServiceConfig2, 103
Channel9, 156
characters, counting, 8
_checkReturn, 7
checksum, 9
cipher suites, 144145
ciphers, Internet Explorer 7, 133
classes, sample code for, 6364
cl.exe, 5
clients (callers), 3
clients, authenticating, 117, 152.
See also authentication and authorization
clients, impersonating, 106
RPC/COM, 227
sockets, 117
CNG (Cryptography API: Next Generation), 135
add-ins, 137138
algorithms, new, 139140

185

crypto-agility, 137138
FIPS and, 142143
missing element, 144
use of, 140142
CoCreateInstance, 85, 91
code, third-party, 58
Code Analysis for C/C++ Warnings (MSDN), 10
code quality, 111
Code Red worm, 55
code security, 111
code signing, importance of, 44, 169
COM client/server configuration
elevation, 26
RPC, 117
COM components, COM Elevation Moniker,
starting, 2526
COM Elevation Moniker, 25
COM Elevation Moniker, The (MSDN), 26
COM interfaces
ATL and, 165
cURL and IUri interface, 131
deprecated crypto features, 148
RSS, 82
COM objects, 2526
credential providers, 159
deprecated, crypto features, 148
parental controls, 165
problems with, privilege reduction, 102103
Comer, Douglas E., 78
commands
icacls, 38
mklink, 45
Common Criteria requirements, 143
security events, 172
communication, with desktop. See desktop,
communication with compatibility, backward, 9
compilers, 45
/analyze, 5, 7, 9
and banned APIs, 8
/GS, 11. See also /GS
JIT, 127
warnings, 910
connections, port, and firewalls, 9192
connectivity, determining, 81
ConnectivityChanged, 81
ConnectNamedPipe, 113, 115
console 0, sharing of, 110
consolidated URL parser (cURL), 130131, 133
const, 5
constant source strings, 8
constants, string, 137
control handlers, and services, 9899
ControlKey, 114
controls, adding, 123
ConvertStringSidToSid, 36

Howard_Index.fm Page 186 Saturday, March 10, 2007 3:01 PM

186

cookies
cookies
/GS, 6467
safeSEH, 68
CreateFileMapping, 112
error (Global\\objectname), 43
CreateNamedPipe, 113
CreatePipeDacl, 102, 118
CreateProcessAsUser, 107
CreateRestrictedToken, 102103
CreateService, 98, 117118
CreateWellKnownSid, 160
Credential Manager, 44
Credential Prompt box, 18
Credential Provider model, 159
credentials, user, prompting for, 2425, 169171
credentials management, access to, 44
CredUIPromptForCredentials, deprecated, 169
CredUIPromptForWindowsCredentials,
169171
CRL (Certificate Revocation List) revocation checks,
145147
CRT (C runtime) functions, 3
CryptAcquireContext, 141
crypto-agility, 9, 136137
in CNG, 137139
cryptographic algorithms, 9, 136137
Cryptographic API 1.0 (CAPI 1.0), 135136
Cryptographic API 2.0 (CAPI 2.0), 135136
cryptographic enhancements, 135136
auditing, improved, 143
CNG algorithms, new, 139140
CNG crypto-agility, 137138
CNG and FIPS, 142143
CNG something missing, 144
CNG use, 140142
crypto-agility, 136137
deprecated features, 148
kernel mode and user mode support, 136
root certificates, 148
SSL/TLS, 144147
cryptographic interfaces, user-mode, supported,
135136
cryptography, banned, 3
list of, 9
removing from codebase, 9
Cryptography API: Next Generation (CNG). See
CNG (Cryptography API: Next Generation)
cURL (consolidated URL parser), 130131, 133
Cutler, David, 60

D
DACLs (discretionary access control lists), 32, 160
daemons, 97
dangling pointers, 55
data

encryption, 7
hashing, 141
MACing, 141
untrusted, 181
user, safe storage of, 30
Data Execution Prevention (DEP), 11, 59, 62.
See also NX (No-Execute up)
enabling, 127128
Internet Explorer 7 defenses, 126129
Davies, Joseph, 78
DCOM, 117
Debug privilege (SE_DEBUG_NAME), 16, 43
debugging
of application compatibility issues, 4244
of Internet Explorer 7 Protected Mode, 126
kernel mode, 163, 175
process, 105
of services, 101
declspec syntax, 3
DecodePointer, 174
defects, software, 4950
denial of service attacks
pipe server, 115116
sockets, 117
deny SIDs, 1920
DEP. See Data Execution Prevention (DEP)
desktop, communication with, 110112
named pipes, 112116
RPC/COM, 117
shared memory, 112
simple message boxes, 112
sockets, 116117
desktop, private, CardSpace, 158
device drivers, loading and unloading, 105
devices, permanent, enabling, 104105
digital signatures, 9, 136
Information Card, 151, 156
directories
allowing low-integrity process writing, 37
integrity level of, setting, 38
LDAP, synchronizing, 105
Program File, access to, 13, 28, 29
user-writable, 42
Windows, access to, 13
disabled warnings, 1011
DisconnectNamedPipe, 115
discretionary access control lists (DACLs),
32, 160
DLLs (dynamic link libraries), 72
ASLR and, 5154
firewall rules and, 9091
GINA, 159
NX bypassing and, 60
document signing, 9
Authenticode, 44

Howard_Index.fm Page 187 Saturday, March 10, 2007 3:01 PM

GetFirewallSettings
domain administration, enabling, 105
domain service accounts, 99
domains, adding computers to, 107
double-free conditions, 5556
downloads, blocking, 166. See also parental controls
_dref_out_bcount(n) macro, 6
drive-by downloads, 121
drop-offs, reducing, 152
DSA, and RNGs, 140
DWORDs, 64, 68, 71
dwServiceSidType, 100
dynamic link libraries (DLLs). See DLLs (dynamic
link libraries)
/DynamicBase linkage, 3, 11
ALSR, 72
browser defenses, 133

E
EBP register, and /GS flag, 64
echo servers, 9192
ecount, 5
eEye, 55
elevated code, starting, 27
elevated tokens, 20
elevation
to administrator, 1820
COM client/server configuration, 26
monikers, 2526
of processes, determining, 2022
prompts, disappearing, 2324
of rouge software, 26
shield icon, 27
encoded pointers, 55
encoding, pointer, 172175
encrypting credentials, 169171
encrypting data, 141
ERROR_ELEVATION_REQUIRED (740) error, 44
errors. See also warnings
450 error, 166
Blocked by Parental Controls, 166
CreateFileMapping (Global\\objectname), 43
ERROR_ELEVATION_REQUIRED (740), 44
OpenSCManager (,SC_MANAGER_ALL_
ACCESS), 43
Event Viewer
certification events, 147
virtualization events, 30
event log, security, 163, 171172
events, logging, 167
_except keyword, 67
exception handlers, 6772
exception handling pointers, 71
Execution Disable (XD), 11
ExitProcess, 61
Explorer, and virtualized processes, finding, 29

187

F
Federal Information Processing Standard (FIPS),
142143
file downloads, blocking, 166. See also parental
controls
file overwrite privilege, 105
file registry, access to, 13
file system, access to, 13
file warnings, 42
files, integrity level of, setting, 38
FillString function, 4, 7
filtered tokens, 20
filtering, disabling, 166167
_finally keyword, 6768
FIPS (Federal Information Processing Standard),
142143
firewalls
configurable properties, 8687
creating rules, 8792
global settings, 8587
groups and interface properties, setting, 9091
network access control, 107110
rule groups, working with, 9394
Teredo, 7880
fixed pointers, 55
Flash, Adobe, 121, 122
FlushFileBuffers, 116
full (full-privilege) tokens, 20, 34
full-cone NAT, 7980
function pointers, 54
randomization of, 58
functions. See also specific functions
annotation of, 3
banned, 8
BCrypt*, 136
C/C++ annotation, example, 45
canonicalization, 130131
cryptographic add-ins, 137138
hash, 9, 136
heap defense, 57
Information Card, browser support detection, 158
Internet Explorer 7 Protected Mode, 124125
NCrypt*, 136
SHA-1, 136
TBS, 180
URL parsing, deprecated, 131
WinMain, and heap defenses, 5859
fuzzing, 50
FXCop analysis tool, 9

G
gadgets, 181
GetConnectivity, 81
GetCurrentDirectory, 118
GetFirewallSettings, 86

Howard_Index.fm Page 188 Saturday, March 10, 2007 3:01 PM

188

get_IsRuleGroupCurrentlyEnabled
get_IsRuleGroupCurrentlyEnabled, 94
GetLastError, 102
get_LocalPolicy, 108
GetModuleBaseName, 118
GetModuleFileNameEx, 117118
GetNamedPipeClientComputerName, 115
GetNamedPipeClientProcessId, 115116
GetNamedPipeClientSessionId, 116
GetNetworkConnections, 81
GetNetworks, 81
GetPreferredHmacAlg, 141
get_Rules, 108, 109
GetTokenInformation function, 20
GetUserSettings, 165
GINA (Graphical Identification and Authorization),
159
global namespaces, 11011
global objects
creating, and local service accounts, 99
namespace, 106
warnings, 43
Graphical Identification and Authorization
(GINA), 159
/GS, 3, 11
browser defenses, 133
buffer overrun protection, 6467
flaws in, 6772

H
hardcoded algorithms, 137, 148
hash-based message authentication codes
(HMACs), 136
hash functions, 9, 136
hashing data, 141
headers, 8
heap
countermeasures, 58
defenses, 5559, 72
overrun, 57, 173
randomization, 51
heap spraying, 55
HeapTerminateOnCorrupt, 72
high-integrity objects
determining, 3940
labeling, 3739
high-integrity processes, 3234, 37, 4142
high-level privileges, 104106
highestAvailable manifest option, 23
HKCU registry, 43
HKLM registry, 13, 43
HMAC (hash-based message authentication
codes), 136
How Windows Defender Identifies Spyware, 168
Howard, Michael, 1, 49, 83, 130, 181
HTML, 121, 123

clipboard access, Internet Explorer 7, 132


gadgets, 181
Identity Selector, Information Card, 157
HTTP remote file access, 145
HTTPExemptionList, 167
Huitema, Christian, 77, 80
Humphrey, Watts, 50, 97
Hungarian notation, 8

I
IBM system, and GINA, 159
icacls command/tool, 38, 41, 101
Ichiro persona, 17
ICredentialProvider interface, 159
IDA overflow advisory, 55
Identity Provider, 152, 153
Identity Selector, 156, 157
IEGetWritableFolderPath, 124
IEGetWriteableHKCU, 124
IEIsProtectedModeProcess, 124
IEIsProtectedModeURL, 125
IELaunchURL, 125
IEnumVARIANT, 109
iepmapi.lib, 124
IESaveFile, 124
IEShowSaveFileDialog, 124, 125
IEUser.exe, 125
IExplore.exe, 125
IFeedsManager, 82
IInternetSecurityManager, 131
IInternetSecurityManagerEx, 131
IInternetSecurityManagerEx2, 131
image files, 121
image randomization, 51
IMG tags, 132
ImpersonateNamedPipeClient, 17, 106, 112
implementations (callees), 3
_in macro, 5
inappropriate content, restricting. See parental
controls
#include sal.h, 7
Independent Software Vendors (ISVs), 159, 167
INetFwPolicy2, 108
INetFwRules, 109
INetFwServiceRegistration, 108
INetwork::GetCategory, 82
INetwork::GetDomainType, 81
INetworkListManager, 81
INetworkListManagerEvents, 81
Information Cards, 151153. See also Windows
CardSpace and Information Cards
browser support, detecting, 158
communicating parties, 152
creation of, 156
display Information Card use, 154

Howard_Index.fm Page 189 Saturday, March 10, 2007 3:01 PM

local namespaces
PIN protection, 154
programmatic access to, 156157
user-issued, 152153, 157
INI warnings, 43
IniFileMapping registry settings, 43
_in_opt macro, 5
_inout macro, 5
_inout_bcount_full(n) macro, 6
_inout_bcount_part(n,m) macro, 6
input buffers, TPM, 180
Integer Handling with the C++ SafeInt Class
(LeBlanc), 55
integer manipulation, computer capability, 55
integer overflow warnings, 910
integrity levels, 1314, 3237
custom, 34
integrity SIDs, 34
low-integrity processes, write locations, 37
object integrity levels, determining, 3940
object integrity levels, setting, 3739
rules for, 40
setting, 45
integrity masks, 40
integrity models, 40
defensive, 4142
Intel Execute Disable (XD-bit), 59
intellectual property rights, 151
Internet connections, determining, 81
Internet Explorer 7. See also Internet Explorer 7
defenses
changes to, 132133
integrity levels, 32
phishing detection, 154
Protected Mode, 40, 4142, 124126
third-party code, 58
Internet Explorer 7 defenses, 121122
ActiveX control, locking, 131132
ActiveX Opt-In, 122123
AES, 132133
clipboard access disabled, 132
cURL and IUri interface, 130131
Data Execution Prevention (DEP), 126129
Protected Mode, 124126
script URLs, 132
window origin, 133
Internet Protocol (IP), 76. See also IPv4; IPv6
Internetworking with TCP/IP Vol. I (Comer), 78
interprocess communication
protocol (IPC), and integrity levels, 41
I/O completion ports, 98, 113
IP helper, 76
IPsec, 77
IPv4, 7677
Teredo, 7880
IPv6, 7678
Teredo, 7880

IPv6: The New Internet Protocol (Huitema), 77


IsElevated function, 27
IsRuleBookCurrentlyEnabled, 94
IsUserAnAdmin, 21
ISVs (Independent Software Vendors), 159, 167
IUri interface, 130131
IWebBrowser2::get_LocationURL, 131132
IXFeedsManager, 82

J
Java applets, 121, 127
JavaScript, 121, 132
gadgets, 181
Information Card, 158
Jet Propulsion Laboratory research, 50
Johnson, Ken (aka Skywing), 60
just-in-time (JIT) compilation, 127

K
KDFs. See key derivation features (KDFs)
Kerberos tickets, 106
kernel mode, 136
debugging, 163, 175
key derivation features (KDFs), 136
password-based, and CNG, 144
key operations, 143
keys, cryptographic, 136
PIN protection, 154
keywords, safeSEH, 6768
kill-bitting, 123
kloc, 4950
Known list, Windows Defender, 169

L
laptops, undocking, 107
LDAP remote file access, 145
LeBlanc, David, 49, 55, 83, 130, 181
legacy applications, and virtualization, 28
LFH (low fragmentation heap),
enabling, 59
Limited User Account (LUA), 14
linked tokens, 20, 21
linkers. See also individual linkers
/DynamicBase, 3, 11
/NXCompat, 3, 11, 129
/SafeSEH, 3, 11
links, forward and backward, checking, 57
Linux
services, 97
symlink security bugs, 45
Lipner, Steve, 1
Litchfield, David, 67, 68, 71
little-endian format, 6
LoadLibrary, 51, 52
local namespaces, 110111

189

Howard_Index.fm Page 190 Saturday, March 10, 2007 3:01 PM

190

local service accounts


local service accounts, 99, 100
local system service account, 99
local user service accounts, 99
localization, 8
logoffs, forced, 165166
logon desktop, 158
LogonUser, 106
logons, and console sharing, 11011
long-lived pointers, 163, 172
Longhorn server, Windows, and OCSP, 146
LookupAccountName, 102
low fragmentation heap (LFH), enabling, 59
low-integrity objects
determining, 3940
labeling, 3739
low-integrity processes, 3234, 4142
sample code for, 3536
write locations, 37
LUA (Limited User Account), 14

M
Mac OS X, and symlink security bugs, 45
MACing data, 141
macros, 4, 57
shield icon, 27
malloc(), 7
malloc.h, 7
malware
anti-malware, 163, 167168
CardSpace, 154
NX, 60
Web browser attacks, 121
manifest file, 22
requestedExecutionLevel options, 23
manifest tool (mt.exe), 22
Marcelais, Mike, 55
Margosis, Aaron, 43
masks, integrity, 40
MD4/MD5 hash algorithms, 9, 136
m_data pointer, 173
m_dest pointer, 173
medium-integrity objects
determining, 3940
labeling, 3739
medium-integrity processes, 3234
memory, shared, 112
memory quotas, adjusting, 107
merchants, online, and Information Card, 152
message boxes, simple, 112
metadata randomization, blocking, 57
Metasploit project, 60
Microsoft Application Compatibility Toolkit 5.0,
debugging
Protected Mode, 126
Microsoft Kernel Mode Cryptographic Module, 136

Microsoft Management Console (MMC), 2324


Microsoft Open Specification
Policy, 151, 156
Microsoft Research, 49
Microsoft SQL Server 2005 Express, 126
Microsoft Windows Internals (Russinovich), 17
Miller, Matt (aka Skape), 60
MIME handlers, 121
mklink command, 45
MMC (Microsoft Management Console), 2324
Moores Law compensator, 144
Mozilla FireFox v2, 133
phishing defenses, 154
MSGINA.DLL, 159
mt.exe (manifest tool), 22

N
name squatting attacks, 110
named pipes, 112116
namespace
collisions, 110
Information Card, 157
local vs. global, 11011
warnings, 43
NAT (network address translation), 7677
Teredo, 7880
National Institute of Standards
and Technology (NIST), 136, 142
National Security Agency (NSA), 143
NCrypt* functions, 136
.NET Framework 1.1, and Protected Mode, 126
.NET Framework 2.0, and Protected Mode, 126
.NET Framework 3.0, and
Information Cards, 151, 156157
.NET Framework Cryptography, 135136
.NET language, and credential/consent prompts, 25
Netcraft Toolbar, phishing defenses and, 154
NetFwMgr, 108
NetFwPolicy2, 85, 93
NetFwRule, 88, 91
network access, controlling, 107110
network address translation (NAT). See NAT
(network address translation)
network connections, determining, 81
Network Diagnostics Framework, 75
Network List Manager (NLM), 75, 8182
network service accounts, 99, 100
networking defenses, 7576
IPv6, 7678
Network List Manager (NLM), 8182
RSS platform, 8283
Teredo, 7880
Windows firewall, advanced security, 8594
Winsock Secure Socket
Extensions, 8385

Howard_Index.fm Page 191 Saturday, March 10, 2007 3:01 PM

PREfast analysis tool


networks, and security, 8182
NIST (National Institute of
Standards and Technology), 136, 142
NLM (Network List Manager), 75, 8182
No Execute (NX). See NX (No-execute up)
No-Write up (NW) mask, 38, 40, 41
NOP (no-op) instructions, 51
and heap defenses, 55
normal user accounts, 1314, 18
Not Yet Classified lists, 169
novirtualization shim, 31
NR (No-Read up) setting, 38
NSA (National Security Agency), 143
NtSetInformationProcess, and NX disabling, 60
ntstatus.h, 140
NULL, 6, 7
null pointers, 5657, 174175
NW (No-Write up) mask, 38, 40, 41
NX (No-Execute up), 38, 40
buffer overrun defense, 55, 5964
bypassing, 60
enabled versus disabled, 6162
/NXCompat linkage, 60, 61, 72
plug-in compatibility, 6263
/NXCompat linkage, 3, 11
browser defenses, 133
DEP, 129
NX bypassing, 60, 61

O
object ownership, assuming, 106
objects
global namespace, creating, 106
integrity levels, determining, 3940
integrity levels, setting, 3739
local vs. global namespaces, 11011
warnings, 43
Office 2003, and namespaces, 111
Office 2007
ASLR, 54
namespaces, global and local, 111
third-party code, 58
Office Trustworthy Computing, 55
online bank, phishing example, 154156
Online Certificate Status Protocol (OCSP), 145147
Open Specification Policy, Microsoft, 151, 156
OpenBSD, and NX, 60
OpenProcess, 16
OpenSCManager (,SC_ MANAGER_ALL_ACCESS)
error, 43
operating system, process acting as, 106
ordinary user accounts, 1314
Organizational Unit (OU), owner SIDs, 160161
_out macro, 5

191

_out_ecount(n), 4
Outlook 2007, 81
output buffers, TPM, 180181
Owner Rights ACE, 160
owner SIDs, authentication/authorization and,
159161

P
page files, creating, 106
Paget, Chris, 110
parental controls, 163, 164
block file downloads, enabling, 166
code for, 165
error 450, 166
filtering, turning off, 166167
logging events, 167
time limits, 165166
parsing, URL, 130131
password-based key derivation, 144, 154
password management, and local user accounts, 99
password security, and Information Card, 152
password theft, 153154
patents, 151
PCT (Private Communication Technology), 132133
peer-to-peer functionality, 75
phishing attacks, 152
CardSpace and, 153156
PID (process identity), 15
PIN protection, and Information Cards, 154
Pincus, Jon, 49
pipe server attacks, 115116
pipes
handling code, sample, 114115
integrity levels and, 41
named, 112116
pointers
C/C++, 34, 172, 173175
dangling, 55
encoded/encoding, 54, 163, 172175
exception handling, 71
function, 54, 58
long-lived, 163, 172
m_data, 173
m_dest, 173
null, 5657, 174175
policy setting, cipher suites, 144145
port connections, and firewalls, 9192
port-restricted cone NATS, 80
PostMessage, 24
PostQueuedCompletionStatus, 114
Power Users, and access, 1314
PowerShell, and credentials/
consent prompts, 25
PREfast analysis tool, 9

Howard_Index.fm Page 192 Saturday, March 10, 2007 3:01 PM

192

primary process token


primary process token
assigning, 104
creating, 105
Private Communication Technology (PCT),
132133
privilege warnings, 43
privileges
benign, 106107
date and time, 25
Debug, 17, 43
high-level, 104106
integrity levels and, 37, 40, 45
new to Windows Vista, 4445
reducing, 102107
process elevation, determination of, 2022
Process Explorer, 17
and integrity levels, 34
process identity (PID), 15
process priority, base, changing, 107
process warnings, 4344
process working set, increasing, 45
processes, virtualized, finding, 2930
profiling information, acquiring, 107
Program File directory, access to, 13, 28, 29,
4546
Protected Mode, Internet Explorer, 40, 4142,
124126
providers, CNG, 137138

Q
quality gates, 23
QueryInterface, 108, 109
Quicktime, 121
quota, 161

R
RACF (Resource Access Control Facility), 159
RAM, locking, 107
random number generators (RNGs), 136, 140
random numbers, generating, 142
randomization
ASLR, 51
heap base, 58
metadata, blocking, 57
stack, 5455
ReadFile, 113
Really Simple Syndication (RSS) platform, 76, 8283
RealPlayer, 121
RegisterServiceCtrlHandlerEx, 98
registry warnings, 43
Relying party, Information Card, 152
Relying Party Certificate thumbprint not specified
warning, 157
remote procedure calls, 117

remote systems, shutting down, 107


requestedExecutionLevel manifest options, 23, 31
RequestedPrivileges, 22
Windows XP bug, 23
requireAdministrator manifest level, 23
errors/warnings, 4344
RequiredPrivileges, 103
Resource Access Control Facility (RACF), 159
restricted cone NATs, 80
restricted tokens
access checks, 101
privilege reduction, 102103
RestrictService, 108109
revocation checks, 145147
server, 153
RFC 2560, 145
Richter, Jeffrey, 67
RNGs (random number generators), 136, 140
root certificates, 148
RPC/COM, 117
RSS (Really Simple Syndication) platform, 76, 8283
Russinovitch, Mark, 17

S
SACL (system audit access check), enabling, 105
/SafeSEH, 3, 11
browser defenses, 133
buffer overrun protection, 6772
SAL annotation, 3
buffers, 34
bug prevention, 2
C/C++ string buffers, 2, 38
example of, 45
in existing code, 78
macros, 57
syntaxes, 3
Salazar, Abby, persona, 17
Salazar, Toby, persona, 17
sal.h header file, 8
salts, and PIN protection, 154
Saltzer, Jerome H., 110
SAML (Security Assertion Markup Language), 156
SCdEnrl, 148
Schroeder, Michael D., 119
screen-scraper attacks, 158
script URLs, Internet Explorer 7, 132
scripting languages, 121
SDDL. See Security Descriptor Definition Language
(SDDL)
secure socket extensions, 8385
Secure Sockets Layer and Transport Layer Security
(SSL/TLS). See SSL/TLS (Secure Sockets Layer
and Transport Security Layer)
Security Assertion Markup
Language (SAML), 156

Howard_Index.fm Page 193 Saturday, March 10, 2007 3:01 PM

standard user accounts


security bugs. See also bugs
browser-related, 121122
buffer-related, 2
symlink-related, 45
security defenses, 163. See also
specific defenses
Security Descriptor Definition
Language (SDDL), 3738
integrity masks, 40
owner SIDs, 160161
SIDs, 102
Security Development Lifecycle (SDL), 3, 8
Security Development Lifecycle, The (Howard and
Lipner), 1
security event log, 163, 171172
security ID (SID). See SIDs (security IDs)
security log, generating entries, 104
security models (integrity models), 40
security quality gate, 3
buffers and, 4
security quality requirements, 311
Security Support Provider Interface (SSPI), 84, 117
security token service (STS), 152
SendMessage, 24
Serpent encryption, 137, 138
server authentication, and phishing, 153
service accounts, 99102
Service Configuration Manager (SCM) access
configuration, 43
service control manager (SCM), 98
service principal name (SPN), 84
service providers, and Information Card, 152
service SIDs, 100102
ServiceMain function, 98
ServiceRestricted, 108
services
desktop communication, 110117
lessons, 117118
network access control, 107110
overview, 9799
privilege reduction, 102107
service accounts, 99102
SeTakeOwnership, 161
/setintegritylevel argument, 38
SetMIC tool, and low-integrity testing, 37
SetSecurityDescriptorDacl, 118
SetServiceStatus, 98
SetSystemFileCacheSize, 107
SetThreadToken, 17
SetTokenInformation, failure of, 37
SHA-1, 136
SHA-2, 139
SHA512, 9
shared memory, 112
shatter attacks, 24, 110

193

shell codes, ease of obtaining, 61


ShellExecute function, 2425
SHGetKnownFolderPath, 124
shield icon, 27
shims, no virtualization, 31
Shipworm, 78
SHLoadIndirectString, 90
SideBar, Windows, 181
SIDs (security IDs), 15, 17
deny, 1920
integrity, 24
low-integrity, creating, 3536
owner, and authentication/authorization, 159161
and service accounts, 100102
textual, creation of, 165
sign-in abandonment (drop-offs), reducing, 152
signing
Authenticode, 44
code, 44, 169
documents, 9
Information Card, 151
Signing and Checking Code with Authenticode
(MSDN), 44
Simonyi, Charles, 8
simple message boxes, 112
SiteLock, 131
size_t argument, 6
Skape (aka Matt Miller), 60
Skywing (aka Ken Johnson), 60
smartcards, 152
sockets, 116117
software, defects in, 4950
sound files, 121
source buffers, 8
source strings, constant, 8
sources and sinks, 117
spoofing attacks, 158, 171
SpyNet, 169
spyware protection, 167168
SSL2, 132133
SSL3, 132133
SSL/TLS (Secure Sockets Layer and Transport
Security Layer), 135, 137, 144145
CardSpace connection, 155
phishing attacks, 153, 155
revocation checking and OCSP, 145147
Security Support Provider, 144
server authentication, 153
stack buffers, and stack
protection, 50
stack diagram, sample, 66
stack randomization, 51, 5455
Standard Annotation Language (SAL). See SAL
annotation
standard user accounts, 1314, 15

Howard_Index.fm Page 194 Saturday, March 10, 2007 3:01 PM

194

Standard User Analyzer tool


Standard User Analyzer tool, 4244, 46
StartService, 118
static analysis, 3
strcat function, 11
strcpy function, 11, 173
string buffers, and SAL annotation, 38
string constants, 137
structured exception handlers (SEH), 67
Structured Exception Handling (MSDN), 67
Suite B requirements, 135, 137, 139, 144, 148
Sun Solaris operating system, and NX, 60
SvcName, 109
symbolic links (symlinks), 45
symlinks, 45
symmetric NATs, 80
syntax, SAL, 3
SysAllocString, 109
SysFreeString, 109
system ACL (SACL), and integrity level setting, 37
system audit access check (SACL), enabling, 105
system environment, manipulating, 105
system time, modifying, 45, 106
system-wide object warnings, 43
System.IdentityModel namespace, 157
System.InvalidOperationException, 143

T
tags, IMG, 132
TakeOwnership, owner SIDs, 161
Task Manager, and virtualized files
determination, 29
TBS (TPM Base Services), 177
Tbsip_Submit_Command, 180
TCG Software Stack (TSS), 177178
Teredo, 76, 7880
terminate on corruption code, and heap defenses,
5859
third-party code, 58
thread tokens, 17
threat modeling, 1
time limits, setting, 165166
time of day, system, modifying, 106
time zone, system, setting, 45
TLS, 132133
token warnings, 43
TokenElevationTypeDefault, 21
TokenElevationTypeFull, 21
TokenElevationTypeLimited, 22
tokens. See user tokens
TokenUIAccess, 24
TPM (Trusted Platform Module), 163, 175177
low-level access to, 177181
TPM Base Services (TBS), 177
Trusted Computing Group, 175, 176

Trusted Platform Module (TPM). See TPM (Trusted


Platform Module)
Trusted Sites zone, 133
_try keyword, 67
try-except block, and exception
handling, 71
TSS (TCG Software Stack), 177178

U
UAC (User Account Control). See User Account
Control (UAC)
UAC-friendly user data storage, 30
UAP (User Account Protection), 14
UDP packets, Teredo and, 7880
uiAccess manifest element, 23
UIPI (User Interface Privilege Isolation), 24
Understanding IPv6 (Davies), 78
Unicode, 6
Universal Plug and Play (UPnP), 86
Unix
access control, 160
root account, 99
services, 97
symlink security bugs, 45
Unknown SID type bug,
Windows Vista, 34
unprivileged users, 14
untrusted data, 181
UPnP (Universal Plug and Play), 86
URIs, 130131
URL filtering, disabling, 166167
URLExemptionList, 167
U.S. Government Protection Profile for Single-Level
Operating Systems in Environments Requiring
Medium Robustness v1.67, 143
User Account Control (UAC), 1314, 1415, 40
administrator application runs, requiring, 2224
administrator elevation, 18
administrator with approval mode, 1820
COM components with COM elevation moniker,
starting, 2526
credentials or consent, application prompt for,
2425
disabling, advising against, 45
elevated managed code applications, starting, 27
options, checking, 44
process elevation, determining, 2022
token format, updated, 20
User Interface Privilege Isolation (UIPI), 24
user tokens, 1517
User Account Protection (UAP), 14
user credentials, prompting for, 2425, 169171
user data, safe storage of, 30
user interface considerations, 2728

Howard_Index.fm Page 195 Saturday, March 10, 2007 3:01 PM

Windows Script Host (WSH)


User Interface Privilege Isolation (UIPI), 24
user mode, 136
user-name/password security, and Information
Cards, 152
user tokens, 1517
administrator elevation, 18
administrator with approval mode, 1820
assertions and, 156
primary process, assigning, 104
restricted, and access checks, 101
token format, updated, 20
token levels, 2122
warnings, 43

V
VARIANT_BOOL, 9394
VBScript, and TPM, 177
verification, certificate. See certificate verification
VeriSign, 152
video formats, 121
Viega, John, 181
virtualization, 2831, 42
disabling, 3132
as temporary fix, 45
viewing, Event Viewer, 30
virtualized processes, finding, 2930
VirtualProtect function, 60, 62
browser defenses, 129, 133
Vista International, 132
Visual Studio 7.0, /GS flag, 64
Visual Studio 2005
administrator-only applications, 22
ASLR, 52
code quality, 3, 4, 7, 8, 9, 11
exception handling, 68, 71
/NXCOMPAT, 129
Visual Studio 2005 Team System, 5
Vittorio Bertocci: WS-TrustUnder the Hood, 156
volume management, enabling, 105
VulnerableFunc function, 6567

W
/W4. See warnings, warning level 4
warnings, 4, 7. See also errors
6204, 10
/analyze, 10
Application Verifier, 11
buffer overrun, 9
C4996, 8
C6387, 7
compiler, 910
disabled, 1011
file, 42
FXCop, 11

195

Information Card, 157


INI, 43
integer overflow, 910
namespace, 43
object, 43
process, 4344
privilege, 43
registry, 43
static analysis, list of, 10
suppression of, 1011
token, 43
warning level 4, 4, 9
Web browser security threats/attacks, 121122.
See also Internet Explorer 7 defenses
Web site filtering, disabling,
166167
Web site restriction. See parental controls
whoami/fo list /all command, 1617, 1819, 34
Wikipedia, 24, 77, 110
Wille, Christophe, 27
WinCreatorOwnerRightsSid, 160
wincrypt.h, 137
window origin, Internet Explorer 7, 133
Windows 95, and user accounts, 13
Windows 98, and user accounts, 13
Windows 2000
LogonUser, 106
user accounts, 1314
Windows CardSpace and
Information Cards, 151152. See also
Information Cards
Information Card data flow, 152
phishing, 153156
private desktop, 158
programmatic access, 156159
summary, 159
Windows Communication
Foundation (WCF), 157
Windows Defender, 163, 167168
Not Yet Classified lists, 169
Software Explorer, 169
Windows Defender Antispyware Cycle, 168
Windows directory, access to, 13
Windows Filtering Platform, 76, 87
Windows Firewall with Advanced Security, 76
Windows ME, and user accounts, 13
Windows Media Player, 121
Windows NT
GINA, 159
NX, 60
user accounts, 13
Windows Parental Controls (WPC). See parental
controls
Windows Script Host (WSH),
and credential/consent prompts, 25

Howard_Index.fm Page 196 Saturday, March 10, 2007 3:01 PM

196

Windows Server 2003


Windows Server 2003
buffer overrun defenses, 49
Information Card, 151
namespaces, 110, 111
.NET Framework 3.0, 156
Network Location Awareness, 81
NX, 60
pointer encoding, 172
security events, 172
SHA-2, 139
user accounts, 17
Windows SideBar, 181
Windows sockets, 7
Windows Updates (WU), and root certificates, 148
Windows versions prior to
Windows Vista
heap defenses, 58
integrity protection, 32
NXCOMPAT, 62
token format, updated, 20
user accounts, 1314, 18
Windows Vista
deprecated features, 131, 148, 169
determining version, 164
Windows Vista Software Development Kit
CNG, 140
code quality, 3, 5, 8, 9
SID creation, 165
Windows XP (SP2)
ASLR and, 51
browser defenses, 122
buffer overrun defenses, 49
heap defenses, 57
Information Card, 151
namespaces, 110, 111
.NET Framework 3.0, 156
Network Location Awareness, 81
NX, 60

peer-to-peer functionality, 75
pointer encoding, 172
RequestedPrivileges bug, 23
root certificates, 148
SIDs, 160
user accounts, 1314, 17, 28, 42
Windows Firewall, 87
WinHTTPExemptionList, 167
Winlogon, privileges and, 44
WinURLExemptionList, 167
WinVerifyTrust, 148
WlxLoggedOutSAS, 159
WMI interfaces, and TPM, 177, 181
WMI objects, and filtering, 166167
working set, process, increasing, 45
worm, Code Red, 55
WpcuSidStringForCurrentUser, 165
WpcuSidStringFromUserName, 165
write down, not write-up, 32
WriteData, 173
WriteFile, 113, 115
WriteProfileXXX, 43
Writing Secure Code (Howard and LeBlanc),
49, 83, 92, 117
WS-* protocols, 151
WSAImpersonateSocketPeer, 84
WSARevertImpersonation, 84
WSASetSocketPeerTargetName, 84
WSASetSocketSecurity, 8385
WTSEnumerateSessions, 112
WTSSendMessage, 112

X
X.509 certificates, 136
XEnroll, 148
XML documents, digitally signed, 151, 156

Michael Howard
Michael Howard is a senior security program manager in
the Security Engineering team at Microsoft, and an architect of the security-related process improvements at the
company. He is the co-author of many security books,
mostly with David LeBlanc including the award-winning
Writing Secure Code, 19 Deadly Sins of Software Security,
and the Security Development Lifecycle. He is an editor of
IEEE Security and Privacy, and the series editor of the
Microsoft Press Secure Software Development series.

David LeBlanc
David LeBlanc is a senior developer in the Microsoft
Office Division's Trustworthy Computing team. In
addition to writing code, he helps advise Office on
security issues and how to implement the SDL. He has
co-authored several security books, mostly with Michael
Howard. David has worked in many aspects of the
security industry, ranging from anti-fraud for telephony
companies, leading the development team for an awardwinning network security assessment tool, penetration
testing for Microsoft's network security group, and was a
founding member of the Trustworthy Computing
Initiative team. When not writing books, he'll be found
somewhere in the Cascades on his horse.

You might also like