Friday, January 06, 2006

Im working on a new utility to help systems guys fight spyware on their systems. I was quite frustrated trying to get one off my Mother's machine, random named exes would keep appearing, even after safe mode boots and removal of hklm\software\microsoft\windows\run keys. I tried also 'pausing' the process using process explorer from sysinternals with limited success. So.. now Im writing a kernel mode driver to help combat this.

For starters, lets visit the short list of how all things can load on the system.

 

ShellExecute Hooks
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Explorer\ShellExecuteHooks

Shell Delay Load Objects
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\ShellServiceObjectDelayLoad

URL Search Hooks
HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\URLSearchHooks

App Init DLLs
HKEY_LOCAL_MACHINE\Software\Microsoft\WindowsNT\CurrentVersion\Windows, AppInit_DLLs

Download Manager
HKEY_LOCAL_MACHINE\Software\Microsoft\Internet Explorer, DownloadUI
HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer, DownloadUI

Notification Packages
HKEY_LOCAL_MACHINE\Software\Microsoft\WindowsNT\CurrentVersion\Winlogon\Notify

 

User\Start Menu\Programs\Startup;
All Users\Start Menu\Programs\Startup;
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Run;
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run;
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\RunOnce;
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\RunOnce;
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\RunServices;
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\RunServices;
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\RunServicesOnce;
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer\Run;
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\RunOnceEx;
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Winlogon, Shell;
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Winlogon, System;
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Winlogon, VmApplet;
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Winlogon, UIHost;
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Winlogon, Userinit;
HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\Windows, run;
HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\Windows, load;
HKEY_LOCAL_MACHINE\Software\Microsoft\Active Setup\Installed Components;
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager, BootExecute;
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows CurrentVersion\Explorer\BrowserHelperObjects
win.ini, load;
win.ini, run;
system.ini, shell.

They can also install themselves as services:

HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services

All of these locations can be exploited.

1/6/2006 12:07:58 AM (Eastern Standard Time, UTC-05:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Thursday, January 05, 2006

So Im trying to compile a kernel mode driver I'm writing against the ddk rather than using vs.net.

First off, to use visual studio, read:

http://tiger.la.asu.edu/Quick_Ref/DeviceDriver.pdf

as well as there is a nice batch at http://www.osronline.com/article.cfm?article=43

but everyone says "hey - use the ddk - that what the compiler is there for"

Ok, so I keep getting an error on this line.

PHYSICAL_ADDRESS    PhysicalAddress; <-- error here -

PhysicalAddress = MmGetPhysicalAddress((void*)block);

 

error:

 error C2275: 'PHYSICAL_ADDRESS' : illegal use of this type as an expression

hmm... its used throughout the ddk samples that I can build. So I try PVOID, void*, ULONG all with the same result.

Then it occurs to me - the types are recognized, how about moving the defs to the top of the procedure (sorry - I've been so used to modern compilers

where you can gladly declare vars anywhere) and voila. Thats an hour of my life I'll never get back - thanks ddk guys for packaging that wonderful compiler with the ddk!!

 

 

1/5/2006 11:56:31 PM (Eastern Standard Time, UTC-05:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Wednesday, December 28, 2005

Sometimes there is a need to control when a page is accessed through a link and bookmark it. For instance,

your company sells a product that should only be valid for a certain time, or provides access to a special deal.

Every page then needs to include checks to determine if the item in question is valid or not.

ex.

www.secure-coding.com/ProductDetails.aspx?id=68

So a check needs to be made to the database, requiring an extra hit on what may be an already busy system.

If you have items that expire quite often, here is an alternative:

www.secure-coding.com/ProductDetails.aspx?id=68&expires=12282005

Now this is quite obvious of course on how one can get around that. However, encrypting it becomes:

www.secure-coding.com/ProductDetails.aspx?54754a68666e3839467646496659745a7467574750773d3d

A page can then determine if the access is still valid.

Still yet another usage

www.secure-coding.com/Admin/DeleteItem.aspx?id=68

Two scenarios can occur, if you use the querystring to manage items in a database, its quite easy to select the wrong one in your recent history.

One alternative is when a link is generated to DeleteItem.aspx, generate a timestamp. If you use a common page baseclass, then that baseclass can decrypt the querystring and check for an expiration date. If it has expired, the user can be redirect, etc.

Once again I advocate encrypting the querystring. I love it : )

Yes - this can be attacked, as can just about anything - but provides an extra layer of data protection and a means to timestamp your links.

This is especially useful when users have very old links they bookmark and you want an easy way to check the lengths of time users keep old links, and refer them to new/updated links.

 

 

 

12/28/2005 5:26:58 PM (Eastern Standard Time, UTC-05:00)  #    Disclaimer  |  Comments [0]  |  Trackback

Heres just a quick list of tips I tell people

1. Dont use embedded queries, use stored procedures, avoid sp_executesql

2. Remove all < > -- ' / \ from input strings. You will need to write a loop that filters multibyte sequences after single byte sequences and loops until no more can be found. Because for ex.

hello-/-john

if you remove the / you are left with hello--john, and thats a problem.

3. Refilter ALL input, including querystring. If you provide a link www.somesite.com/products.aspx?id=906B

Assume someone is messing around with the url and trying things like

www.somesite.com/products.aspx?id='--

to test for sql injection attacks.

4. Make sure your login pages are https. I know - seems like a given, however many sites actually have login pages that are not https, but post to https pages, hence the data is still secure.

However, the 'lay user' doesn't see the little 'secure' lock in their browser and don't think it is secure. Believe it or not I've heard quite a few complaints from users trying to access sites in that manner.

5. Encrypt all query string information - I should be posting some code shortly for this.

6. Configure error pages for all of your applications (in turn make sure your <customErrors> section in web.config is set to RemoteOnly so remote users wont get asp.net error messages.

Catch errors in global.asax application_onerror and log your errors at least to a file. If you log to the event log, remember to give asp.net permissions to the eventlog registry key

http://support.microsoft.com/default.aspx?scid=kb;en-us;329291 (I believe if you give aspnet (2000,xp)/network service (2003) permissions to

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Eventlog\Application

you should be ok. Log to a file first, since that is the method most likely to work. If you log to a db and that fails, your code needs to continue logging, hence easiest to log to a file first. TEST THIS for every application you deploy.

 

 

 

12/28/2005 12:33:11 AM (Eastern Standard Time, UTC-05:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Wednesday, November 30, 2005

From a local machine, it seems maxing out your network connection can cause a terminal service session to disconnect.

From there, its a small step to enumerate connected users, hammer them and use up available sessions.

Only solution I can think of is qos packet scheduling. I'll have to investigate this one further.

11/30/2005 4:26:30 PM (Eastern Standard Time, UTC-05:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Tuesday, November 15, 2005

Nice work on the automatically generated code for the login component -

If you name your page login.aspx and put a login control on the page, it seems theres a namespace problem and the code casts to a (Login) control, which really casts to your page class - hence the problem, because it's expecting a Login control instead. Solution is to rename your page class.

1. Rename your page to AccessLogin.aspx for example

2. Rename (right click on it and select refactore-rename for best results) your class in your code behind from Login to AccessLogin

3. Update your "Inherits" tag on your .aspx page from Inherits="Login" to Inherits="AccessLogin"

That should do it.

11/15/2005 11:11:05 AM (Eastern Standard Time, UTC-05:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Thursday, November 03, 2005

Be careful of embedding script in server controls, it won't work and can very well lead to information gathering.

This is of course a very simple example. Code is not processed in this case:

<asp:HyperLink id="HyperLinkStatement" NavigateUrl="MyUrl.aspx?<%=GetSecureInformationFromEncryptedFile("c:\\somefile.txt")%>" style="Z-INDEX: 101" runat="server">Download</asp:HyperLink>

This will not evaluate the method. I always find it interesting the results you get when searching for asp code on the net. Because of misconfigurations or server migrations, you can view the entire source code for various sites out there.

11/3/2005 10:23:06 AM (Eastern Standard Time, UTC-05:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Tuesday, October 25, 2005

Accessing a remote resource

First understand the difference between LOGON32_LOGON_INTERACTIVE and LOGON32_LOGON_NETWORK

Second understand that if:

1. You are on a machine (Machine A) that is not part of the domain

And

2. You are trying to access a domain machine (Machine B) using domain credentials from Machine A using LogonUser

This will not work. Machine A doesn't know about this domain, so getting a token with information for some domain that is unknown is useless.

You must be using a domain account. One mistake that is quite common deals with a misunderstanding about logging on users. If I make a call to LogonUser and specify LOGON32_LOGON_NETWORK, there is a search order for domain controllers to validate that name. If you have specified the local machine, then there is no validation unless of course you are on a domain controller. If you are trying to validate against another machine on the network that is NOT PART OF A DOMAIN - you cannot validate these credentials through logonuser. You must map the connection as described below. Even if the local login and password match that of the remote machine, this will not work. It can be confusing, because if I try to access machine b from Machine A, and they both have an administrator account with a different password that I need to specify in the credentials from machine a:

MachineB\administrator

in order to validate the user on machineb. So one would think I can call logon user and specify a remote machine name. False. You cannot (as far as anything I am aware of). So then how does Windows do it you say, or such things like runas.exe? Think what happens in a remote machine network access. Your system tries to setup an SMB session. The remote server requires more information and sends back STATUS_MORE_PROCESSING_REQUIRED. Your system sends over the appropriate authentication information. You then access the interprocess communication share at \\MachineB\IPC$ and once this is established (with a proper account) can perform your network request (ex. c:>dir \\machineb\someshare)

How can you then achieve this behavior? Simply enough, in this case you use the WNetAddConnection2 api to establish a session to \\machineb\ipc$. Once that session is established you have "remote permissions" for your current login and can then do your mojo. You are using SMB session information, and not logonuser to achieve this.

 

10/25/2005 8:19:08 PM (Eastern Standard Time, UTC-05:00)  #    Disclaimer  |  Comments [1]  |  Trackback

I realize this doesn't relate to secure coding (Although something quickly comes to mind of a way to modify a user's path statement to load libraries they didn't intend to) but felt this was important to post.

I was troubleshooting a coworkers system that was running extremely slow. Running calc.exe would take at least a minute to load. I noticed the network icon was lighting up every 8 seconds or so with a transmit but no receive. One thing to note, once she unplugged her machine from the network, response time was normal again. Loading up tdimon from www.sysinternals.com (netmon would have worked as well but was not yet on this system) I was seeing an attempt to contact a remote machine on port 445. The first though was something had hooked the shell and was receiving notifications of program loading and trying something shady. Turned out to be a bit simpler. The path statement contained a unc path so every program searched this path for dependencies upon loading. I would check your path statements to make sure this isn't there, as this would affect the loading of almost every program on the system. When the machine was unplugged, the network services knew there was no network interface to use to try to contact the remote machine, and thus performance was restored.

You can see here the process that is used and how a dll is resolved upon loading. This process can be examined a bit more in detail at:

http://msdn.microsoft.com/msdnmag/issues/02/03/Loader/

The call stack order something like this:

LdrLoadDll
    LdrpLoadDll
        LdrpCheckForLoadedDll
        LdrpMapDll
            LdrpCheckForKnownDll
            LdrpResolveDllName
               RtlInitUnicodeString    
               LdrpResolveDllNameForAppPrivateRedirection
               LdrpSearchPath
                 RtlDetermineDosPathNameType_U    
                 RtlInitUnicodeStringEx
                 RtlDoesFileExists_UstrEx
                 LdrpResolveFullName

So when the path is parsed, a remote unc will be checked om RtlDoesFileExists_UstrEx

Recommendation: Remove all unc paths if you are able to from your path statement

 

 

 

 

10/25/2005 3:27:19 PM (Eastern Standard Time, UTC-05:00)  #    Disclaimer  |  Comments [1]  |  Trackback
 Monday, October 10, 2005

If you run runas.exe with the /netonly flag and specify totally invalid user credentials, it never even checks those credentials until you access the network.

You would think the resulting program that runs (cmd.exe for instance) would check that first, especially since the window title is:

cmd(running as machinename\someinvalidaccount)

Just an oddity to watch out for. You are not actually authenticated with network permissions until you attempt to use those network permissions.

In other news tokenmon from sysinternals has caused a system crash twice now in as many days on two separate systems.

The first was in my physical server in lsass.exe the second occured on a virtual server and it just rebooted the virtual server.

Don't get me wrong, I absolutely love their utilities and they've served me well for a long time. The guys from sysinternals should be role models for everyone in the IT world - but the utilities shouldn't crash my servers. I'm going to try to get an exact duplication as Im concerned about the possibility of a denial of service on any system running it.

I've sent an email to them, haven't heard anything back though.

 

10/10/2005 4:37:13 PM (Eastern Standard Time, UTC-05:00)  #    Disclaimer  |  Comments [0]  |  Trackback