Thursday, December 23, 2010

DC225 Status update....

In Baton Rouge there are limited resources for an individual, working on their own merit, to have access to equipment such as supercomputers and vast distributed networks without being affiliated to the local college. Even in the local college (LSU, etc..) case - the hardware is generally substandard. Well - for those of you who are members, for an electricity fee in operating the equipment (think a few bucks a month or 'as use' costs) you will have a
1) Welding shop
2) Woodworking Shop
3) RF Development area
4) About a dozen or so beefy rack servers to run your services on
5) And encrypted chat/file distribution network
6) An area to fly/drive/burn/sink shit in.
7) The envy of your peers.
8) A wireless (G/N) shot of 8.9 miles in any direction (thus damn good listening capabilities for those researchers in the 'quieter' analysis of wireless). We wish to get Wi-Max - but we need enough subscribers to operate a WiMax AP for the entirety of BR...
9) Oh yeah... a damn super computer. A modern fridge size ,1 million USD $$$, beast. You have to notify us of when you want power and you have to pay for the juice (it runs on 220). But hey... got a genome to decode? We have a solution for that... lol

Think of it as a YMCA of hacking... Anyone interested? Well ... the facility has already been procured. The super computer is already in hand. So are about a dozen workstations, 10 or so monitors/keyboards/mice, 10 Poweredge servers with between 4-12 gigs of ram each (all are dual Xeon setups). We also have the woodshop and welding area (we need doors for these area... but we are working on building those now). This has a parking area for about 10 or so cars in a secluded ranch setup 8 miles from city center. Let's just say its 13% of the entire suburb, plus a 3 acre pond to enjoy your *non ecosystem destructive* water craft/toys.

Well... I am off to setup a deployment server for everything. Time to get cracking.

I want to give a shout to JCaffeine and Subnet11... great folks doing great things. Thanks for the hardware Caffeine... you are always on point for this and a true innovator. Subnet, you can script a config for a cisco anyting faster than anyone I have ever witnessed. And thanks for the on loan network stuff. And to Capitalism for making all this bad ass free shit FREE. Lets get to hacking....

Friday, January 8, 2010

TS Penetration and Defense

Thanks to Datalus[t] for providing this article on the basics of Terminal Services attacking and defense. To see more of this sort of thing, sign up for the group:

Cracking & Defending a Terminal Server

Blakdayz has been on my back about getting some content in here (and rightfully so), so I started pondering what type of content would be relevant to our members. My professional IT experience consists almost exclusively, and lamentably, to network administration in Windows environments. However, since I'm not the only one in this boat, I thought I would extend a collection of knowledge (read: no original thoughts here) on Terminal Services security to the group and allow for some constructive observations and reflections from others.

This will be a very basic guide, but will require a little knowledge of Terminal Services, the command prompt, and working in a Windows Server 2000/2003 environment will be handy. No programming knowledge required; we are going to be script-kiddies for the day.

I'll also make the obvious note that this information is for educational purposes only. I don't recommend doing anything listed here on a server that you do not have permission to touch, as there is a high chance you will be swiftly busted. For the sake of brevity


Terminal Server is the server component of Terminal Services (now Remote Desktop Services). It's the service that allows you to open Remote Desktop (the client component) on a workstation or laptop and login to a remote server. Businesses everywhere use terminal servers to allow remote users to access applications from outside the network. It's also very popular for remote administration. Terminal Server listens on port 3389, and one of the first things a green Windows admin learns how to do is enable remote access through TS and setup a rule in the firewall to allow port 3389 to translate to the internal server.


We are going to assume, for the sake of avoiding argument, that we only have access to port 3389 (or whatever port the server is listening on), and there are no other vulnerable servers on the same network segment that would present a more appealing target. It's important to remember that brute force attacks, particularly on a properly hardened server, are slow, noisy, and generally juvenile when you consider the wealth of more advanced attack vectors out there. However, since brute force attacks are so prolific, it's important to understand how they work and how to defend against them.

Attacking the Box

First, let's find a vulnerable box. If you already have the IP address of the server you wish to attack, you could skip this step. More than likely, you'll need to do some searching to find a readily attackable box. Here are a few tactics:

Port Scans Away Lads!

Fire up your favorite port scanner (nmap is always a solid choice) and scan away at port 3389. With nmap at the command line, this would be something like:

nmap -PN -p 3389,3390

I'll note here that a common technique for getting more than Terminal Server to share a single external IP address is to use NAT and translate other source ports to a destination of 3389 (Usually the ports just above 3389). This means you should not rule out scanning 3390, 3391, etc. in order possibly turn up additional servers or workstations listening on the victims IP address. I also used the -PN switch to disable pinging the target. Many firewalls have default configurations that do not respond to ICMP messages and we may miss a nice juicy server because of this; after all, we are only scanning two or three ports. If you are targeting a particular area (let's say you want to hack someone in your hometown), you could do a little digging to find out what subnet they operate on in your area and specify that in your scan. If you wanted to target a particular company, dig'ing their domains NS records and looking for something like "" or "" in A/CNAME records is a good place to start, or simply port scan their web server and hope it has TS access turned on (a big no-no, but you'd be surprised).

If you aren't so keen on your IP address showing up in firewall logs (or reside in a country where port scanning is illegal), you can try anonymizing yourself with Tor. Tor bounces your encrypted requests around a random set of relays running the Tor server. Used correctly, you'll appear to be hitting a server from another country entirely. If you have never used it before, head to the Tor Project website and check it out.

Google for TS Web Directory

Many Terminal Servers are also going to have the TSWeb website installed . Try a Google search for "/TSWeb/default.htm" and you will find at least one or two results per page that show a Terminal Server that has port 80 open to the world. TSWeb (Which uses ActiveX) is great for admins because it allows us to simply tell a user to "Go to and sign in" instead of trying to walk them through getting an RDP connection started. However, it's also a great big announcement to the world that a remotely accessible server resides at this address. Small Business Server editions of Windows Server will ship with the remote workplace sites (including TSWeb) disabled from being accessed outside the network, a great security move by Microsoft.

Crack the Box

Once you've spotted a terminal server that is open to accepting connections, it's time to get cracking. Let's look at dictionary attacks first:

There are a couple of great tools to run dictionary attacks against TS boxes, but all of them will require a good wordlist. A wordlist (or word file) is simply a huge list of words that represent all the passwords you are about to try. I would recommend finding a large dictionary file and performing some transformations with a utility such as John the Ripper before piping the output to one of these tools (for example, add the numeral 1 or try capitalizing the first letter of every word). Transformations such as these will obviously increase the time it takes to crack an account exponentially.

There are a few utilities specifically designed for attacking a TS login. TSGrinder is the most popular and widely available, but TSCrack is out there also on some torrent sites (their main webpage disappeared awhile back).

TSGrinder is strictly a dictionary-based attack tool, there are no options (yet) for character-iteration (e.g. trying every combination of characters until a match is found). You'll also need to have the Microsoft Simulated Terminal Server Client Tool (roboclient) in order to run TSGrinder. Once you get everything downloaded and setup, pop in a command like this:

tsgrinder.exe -w wordlist.txt -u administrator -b -n 2

There are a dozen or so options for TSGrinder; the ones I've used here specify my wordlist (wordlist.txt), the account I wish to login to (administrator), the number of threads to run ( 2 ), and the "-b" switch jumps past any banner that is thrown up by the server.

You will almost always want to target the administrator account. The reason for this is that the administrator account typically cannot be locked out despite any lockout policies that have been specified. You are welcome to specify other accounts with TSGrinder, but you'll have to hope the administrator stuck with the default lockout policies to avoid locking out the target user before you've found the correct password. TSGrinder also has a built in feature that will limit the number of attempts on a single login session before opening up a second session. This will prevent you from triggering a 1012 event in the log that may trip an IDS.

There are other options to play with in TSGrinder, including a "1337" mode that performs some common exchanges of characters in your password list (for example, replacing "@" with the letter a). Once a correct password is found, it's all self-explanatory from there.

Defending the Box

Now that we've seen how simple it is to brute force our way past a weak password, let's look at some of the countermeasures that all system admins should be aware of.

Limit Access by IP

This is particularly important for servers that only have remote desktop enabled for administrative purposes. Most sufficiently advanced firewalls can include an ACL to block all inbound traffic and make exceptions for certain IP addresses that wish to connect on port 3389. For a Cisco firewall, your access list might contain an entry like this:

access-list 101 permit tcp host host eq 3389

If you only need to access the server from your office, and your office has a static IP address, there is very little reason to allow the entire internet community to have access to the Terminal Server. If your firewall does not have the capability, you can use the built-in Windows Firewall to control access by editing the scope of the RDP exception rule with a command similar to this:

netsh firewall set service type = Remotedesktop mode = enable scope = custom addresses =,

Use a VPN Tunnel

If you have a large set of users who are accessing your Terminal server, consider installing a VPN client on their machines, provided you have the proper hardware on location. Then we would simply turn off RDP access from outside the network, only allowing users who are physically or virtually connected to our private network to access the server.

Rename the Administrator Account

This is a best practice on Windows servers, but is not often implemented on smaller networks. Renaming the administrator account means that the attacker will need to either know what the correct username is, or have a way to enumerate the UID's and find the administrator username. In addition to renaming the default account, you should always have another account in the administrators group that you actually use to login with and administer the server so that proper lockout policies can be implemented.

Setup Lockout Policies

If you haven't done this already, shame on you! Lockout policies ensure that users (and hackers) only have a limited number of guesses before the account is locked down and are very important in mitigating brute-force attacks. One down-side that should be noted for this: Enabling lockout policies may result in a DoS for a user account if a brute-force attack is attempted. I won't go into the ins and outs of lockout policies, but you can read more on TechNet.

Enforce Strong Passwords

Again, if you turned off the "Complex Passwords" requirement (unfortunately, very common) in Windows Server, shame on you! Most users, given the option, are going to use short, simple, dictionary words that (as we saw in the first section) are very easy to crack given some time. A minimum password length of 6 characters is really the shortest you should go, and simply moving it to 7 will increase the number of permutations by nearly a hundred fold. Again, you can check out account policies on TechNet.

Enable Auditing

This won't prevent someone from accessing the system, but it will help to leave a trail when someone launches brute-force attempts at your server. Enabling Account Logon auditing for successes and failures will ensure that any bad password attempt gets thrown into the security log along with the perpetrators IP address. Combine this with a log analysis tool or IDS and you can have some red flags go up automatically at any brute-force attempts.

Change the Listening Port

It may be a possible headache for your users, but switching to a port besides 3389 for remote services will help hide you from port scanners that are searching for open ports. If your firewall allows you to granularly control port translation, you can simply set it to translate incoming packets from a higher port (lets say 33890) to 3389 before forwarding them to your server. If you are stuck with a SOHO router that can't do this, Microsoft provides a KB article that will walk you through adjusting the listening port for TS. It's not recommended by MS, but should not cause any issues. Just remember to specify the port in your remote desktop connection ( e.g. ).


As easy as these steps are to follow for hardening your Terminal Server, there really is no excuse for having a publicly accessible box with weak policies and passwords. If you have any further suggestions for hardening (or attacking) a Terminal Server, feel free to post below!

- Datalust

Saturday, December 12, 2009

Disabling Strong Naming - A Pirate Method

Note: It should be noted that this is the legit way to get caught. I have only tested this against .Net 3.5 sp1, and only assemblies that are in full trust can be skipped. Patching Strong Naming in mscorlib will get you further than this, without direct fear of being noticed.

Read this:

There are two ways to disable Strong Naming (a pirate way, and a ninja way). The pirate method is by using the built in Strong Naming Tool (sn.exe). The Ninja way is to patch what you need in the mscorlib assembly via Framework injection. Today we will learn to wear an eye patch.
It is possible to, completely or just partially, disable strong name verification for assemblies.

Sn.exe Argument dump for -Vr switch:

-Vr [] []
Register for verification skipping (with an optional, comma
separated list of usernames for which this will take effect and an
optional test public key in ).
can be specified as * to indicate all assemblies or *, to
indicate that all assemblies with the given public key token. Public key
tokens should be specified as a string of hex digits.

While putting your injected GAC assembly files in place and deleting the ngen derivatives, or in your injected method, just hop out and call

sn -Vr *

This will result in a verification skipping entry for all assemblies and all users.

You can, also target a specific assembly by public key token. To disable System.Windows.Forms.dll strong naming verification, you would run (as of .Net 3.5):

sn -Vr *,b77a5c561934e089

So there you have it. Now I am going to test if this works for getting something ngen'd that shouldn't be.

Friday, December 4, 2009

Framework Injection :: Part Two of Two

If you haven't yet, please read lesson one.

Alright, so we have our malicious method's code saved off in a text file malicious.txt. Now we need to generate a complete dump of the victim mscorlib.dll. In order to do this, copy the victim DLL from its GAC location under the \Windows\Assembly\GAC_32\mscorlib\ directory to a temp folder.

Now, if you haven't already, add your SDK location to your PATH environment variable, or just browse to the Microsoft .Net SDK bin folder. If you are running ildasm.exe from the SDK folder directly, remember to modify the location of mscorlib.dll in the following command.

ILDASM / /NOBAR /LINENUM /SOURCE \temp\mscorlib.dll

This will generate a fairly large text file of IL that is mscorlib. Open it and search for the signature line of our victim method. Copy our malicious code over the original code, from the .method to the last '}' bracket. Now, if you got the line renumbering right during lesson one, it will compile back into mscorlib.dll and we can move that back into the GAC. When it loads, the path information is what is used to verify any SN requirements on assembly load.

Compile the modified by running this command (modify this command with the location you wish the output to go):

\Windows\Microsoft.NET\Framework\V2.0.50727\ilasm.exe ILASM /DLL /QUIET /OUTPUT=\temp\maliciousdll\mscorlib.dll

This will generate a suitable malicious replacement for the mscorlib.dll in the GAC.

So copy the mscorlib.dll to the GAC. If you are in a remote shell and the OS is Vista or Win7 and the shell is not running as SYSTEM or builtin\Administrators, you must use the runas.exe command and use a local admin credential set to get this to run.

copy \temp\maliciousdll\mscorlib.dll

You must kill all processes using .Net (the FontCache Service in Vista needs to be stopped, if you get stuck). In Win7, you have to spray and pray on this. I am getting something [a tool] to bypass this together to make it painless.

Alright so now that you have the DLL in the GAC location for the version you are attacking, you must get rid of the ngen registration as well as the actual assemblies. To do this browse to the
C:\WINDOWS\assembly\NativeImages_v2.0.50727_32> .

First, to remove the registration - run the command

ngen uninstall mscorlib

If you are attacking another assembly, just add ' ni' between the filename and extension when running the ngen command.

Search for all files named by running

dir/w/s mscorlib*

Delete those files and their directories. If you are a whitehat and reading this, this is a point you can check - if ngen has no listing for your assembly and / or the directories are gone, it is a pretty good idea you have been infected.

Once you remove all references to the native images, your malicious code will now be ready to run. Execute the Console.Writeline(string) method in a test application and you will see it printed twice. No virus scanner or tool will alert a user that his mscorlib.dll is malicious in any way.

Keep hiding in the noise....


Host Protection and the CLR - How to Bypass It

Since we are in the middle of talking about modifying mscorlib.dll for our own malicious intent, I will tell you guys a little about Host Protection. Host Protection "allows an application hosting the CLR to declare some types of operations off limits for use by hosted code."

Microsoft describes this feature of the CLR as a 'reliability feature', more than a security feature. However 'use specifies definition' and it is used all over the place in mscorlib to restrict untrusted code from executing certain behaviors. Altering it does present a serious reliability issue, but in any case you need to - here is the simple way to remove it.

Fully trusted code will never be disallowed any HostProtectionCategory.

To read more on this subject go to

Take the writline(string):void method from the IL dump of the assembly mscorlib.

.method public hidebysig static void WriteLine(string 'value') cil managed
.permissionset linkcheck
= {class 'System.Security.Permissions.HostProtectionAttribute, mscorlib, Version=, Culture=neutral, PublicKeyToken=b77a5c561934e089' = {property bool 'UI' = bool(true)}}
// Code size 12 (0xc)
.maxstack 8
IL_0000: call class System.IO.TextWriter System.Console::get_Out()
IL_0005: ldarg.0
IL_0006: callvirt instance void System.IO.TextWriter::WriteLine(string)
IL_000b: ret
} // end of method Console::WriteLine

This code specifies the HostProtectionCategory 'UI'. If the calling code is not trusted for UI access, the operation fails to run and throws a HostProtectionException.

Simply delete the specified .permissionset opcode and its value, or alter it (this may cause trusted code to be denied if you are changing the boolean operation. coding...

The resultant code will be:

.method public hidebysig static void WriteLine(string 'value') cil managed
// Code size 12 (0xc)
.maxstack 8
IL_0000: call class System.IO.TextWriter System.Console::get_Out()
IL_0005: ldarg.0
IL_0006: callvirt instance void System.IO.TextWriter::WriteLine(string)
IL_000b: ret
} // end of method Console::WriteLine

Now compile mscorlib.dll using ILASM and stick it back into the GAC using a directory filesystem copy to all child directories c:\windows\assembly\gac_32\mscorlib. Remember to unregister the NGen copies of assembly from all of the c:\windows\assembly\nativeimage locations simply run
ngen uninstall mscorlib
Next delete the files from their locations in native images after you unregister them using ngen. Search for in c:\windows\assembly and delete all copies from the appropriate directories.

Now I have not had to alter this attribute just yet for any reason. If someone has any input to contribute on cases where this would be beneficial to violate... Internet Code in the unprotected zone, etc... don't be afraid to post.

Wednesday, December 2, 2009

Framework Injection Part One of Two - How to Patch mscorlib.dll and put it back in the GAC

“ What the F@#$! A rootkit where?!?!”


Microsoft .Net developers have, from the first iterations of the .Net Framework, taken shelter in a solid security ideology about the code they offer. Strong naming, assembly evidence, etc…. basically “Safety through managed code” was the general consensus. However some had their doubts. About 9 months ago, at a small security conference Erez Metula first gave a speech on .Net Framework Rookits, then he gave a revised version at BlackHat 2009.

Having taken a serious look at this for the past year or (Since DC16 ) I have decided to elaborate on his attempts, and make efforts to ensure a hybrid rootkit – one that can use traditional DKOM (Direct Kernel Object Manipulation) and SSDT/IAT patching to help obscure and persist a .Net Framework Rootkit. And then utilize the .Net Framework rootkit to help persist the unmanaged kit. The busiest code will be managed, making heuristics a very hard endeavor to say the least.

This ‘secure’ ideology is brought back down to earth by a key element in Microsoft’s implementation of the Global Assembly Cache. This fatal flaw brings about new vectors as to what you can do in application layered attacks – which is literally anything you want. I am talking undetected, unfettered, and persisted access to user land / kernel land. This enables you to root the box and along with it all business programs built in .Net. All it takes is some free software and you are set to writing your first .Net Framework rootkit.

I hope you can take more away from this than just another tool or paper. The point here is to transfer a basic understanding about what you can do after you exploit when you find yourself in the need to persist access to a system. No special script tool needed, just pay intimate attention to the detail. Please Enjoy.

-blakdayz ^t

Credits: Erez Metula for his BlackHat conference talk on this – way to bring awareness to this glorious fault

5houtz 2 v1ru5, DT, Carric, Queeg, datalus, Pyro, Ed, and Delchi (he throws one Hell of a party), and KingPin… and to the crew of DC225 & 303 … to the rest – much thanks to the beer and entertainment in the Red Stick & Vegas.

The Tools You Require

These are the droids you are looking for (your tools, go… get them… quickly now):

· ProcMon from SysInternals (Free)

· .Net Reflector by RedGate (Free)

· Visual Studio Express (Free)

· .Net Framework 2.0 SDK (Free)

· A text editor

· Ngen (Native Compiler)

All of these tools are free and easily located. Install them.

>Section A: The gist of the Strong Naming bypass that allows this is an extreme .Net Framework weakness
(read on, I will explain)

It seems that the touted reliance on SN (Strong Naming), and the promotion of its assembly integrity verification propaganda were not entirely truthful on Microsoft’s part. While gacutil.exe may look at this evidence when it is copying a dll to the GAC, nothing looks at evidence, or prevents a true file system copy of this Dll to its appropriate location in the GAC file system. For those that are new to the GAC, it resides at c:\windows\assembly location. If you browse to this location in Windows Explorer, you get a .Net representative interface into the file system. If you drag and drop just any DLL there, you will get the expected gacutil Strong Name violations for a non-strong named replacement.

Important Note

If you alter a .Net Framework assembly that is already strong named, it cannot load an assembly that is Strong Named. Doing so would cause lazy-loaded assemblies to fail the manifest checking of the CLR assembly load operations. You may be able to patch this loading process to the point where you can push yourself into DLLs that do depend on Strong Naming, if you first break the Strong Naming mechanism check.

How do you get around the Strong Naming mechanisms in the GAC and .Net? If you were to navigate to the GAC location directly via a command prompt (shell) you would see a completely different picture. Through the shell you can copy our malicious DLL over the one currently cached – without any interference (provided you have install rights to the box).

To get your new malicious code loaded another step is required. You must wipe any image of the victim DLL from the native images location. The native images location contains non-JIT code that is representative of the .Net managed library. This means there is a machine code variant of most .Net Framework DLLs. This optimizes the speed of the .Net Framework assemblies’ code via bypassing the JIT compiler and just running machine code.

To force load the malicious assembly when something requests it, you must delete this optimized dll from the Native Images location that corresponds to the framework dll you are injecting. This will force load the JIT compliant DLL that you have injected into the referencing clients app domain. We will talk more on this subject when we perform the injection of our target code.

Example: A Different Kind of Hello World Example

Browse to your GAC via the shell. Our example will victimize mscorlib.dll.

1. Change your location to the assemblies directory (it’s the filename of the assembly, minus the extension).

2. List the directory. Notice the version of the DLL and the public key token of the DLL form this directory? This is the VERSION_TOKEN. This is where a .Net assembly’s information in the GAC listing is derived from. When these are loaded, no evidence is looked at (normally it’s a native - not managed DLL - that is loaded). When you delete that native DLL, the system auto-magically looks for it in the GAC and loads it, no checking of the Strong Name of the DLL is done. This is a major design flaw that MS is aware of, but lacks the ability to fix (since, as an administrator, you have access to the file system directly).

7. In Reflector, Select File>Open then browse to the location you copied your DLL to. Click the Open button. Now you can expand the namespace mscorlib and browse to the library CommonLanguageRuntime. Browse to the namespace ‘System’, and find Console. Expand Console and right click the Writeline(string) function. Choose Disassemble from the menu.

Opening ILDASM – If you have installed the SDK at this point you can find it in the ‘Program Files\Microsoft.NET\SDK\v2.0\Bin’ location. In IL DASM select File > Open and locate the malicious code DLL. Expand the System tree menu until you find System.Console. Under System.Console find

WriteLine : void(string) . Double click that entry and you should get the ILASM dump of that function. Copy the entire contents of that file into your text editor.

The method’s IL ASM should look like this:

method public hidebysig static void WriteLine(string 'value') cil managed


.permissionset linkcheck

= {class 'System.Security.Permissions.HostProtectionAttribute, mscorlib, Version=, Culture=neutral, PublicKeyToken=b77a5c561934e089' = {property bool 'UI' = bool(true)}}

// Code size 12 (0xc)

.maxstack 8

IL_0000: call class System.IO.TextWriter System.Console::get_Out()

IL_0005: ldarg.0

IL_0006: callvirt instance void System.IO.TextWriter::WriteLine(string)

IL_000b: ret

} // end of method Console::WriteLine

Take a look at the line IL_0000 thru IL_0006. This code first selects an output method (stdout) and then calls TextWriter:WriteLine(string). We want this action to occur twice for our example project. Note that there is no .locals directive, and we do not wish to change the value of .maxstack, we just want the already encoded action to occur twice.

Injecting IL ASM Basics

Line Numbering

In regards to those line numbers of the IL dump. They are necessary to get right, because when we recompile they need to be straight. There are shortcuts around some of these steps, but line numbering skill is necessary as the research involved in accomplishing unlocks other nuggets of understanding.

Without using a tool there is a way to know what line comes next and it is based on what IL opcode is getting called on that particular line. You simply add up the number of bytes offset by calling that opcode and your result will be your following line number. This is necessary when we plan on injecting our code into Microsoft’s libraries. To get a good idea of this, look to ECMA 335 Partition III Opcode specification.


A very good example is the following code, taken from the System.Console.WriteLine(string) function IL above:

IL_0000: call class System.IO.TextWriter System.Console::get_Out()

IL_0005: ldarg.0

The first line here with “IL_0000:”. In this line of code, we have the ‘call’ opcode with 4 parameters which are (per the ECMA Specs):

the method to call, and the number, type, and order [implied] of the arguments that have been placed on the stack to be passed to that method, as well as the calling convention to be used”

So that’s four(4) parameters, plus the opcode itself (28 in this case), which is 5 total bytes .So, after the ‘call’ line, the next following line number should be 5 more than the line that contained the ‘call’ opcode. This is the line number offset (a 5 byte offset in the ‘call’ opcode case). When mating this code to another function, we would take a look at the line number immediately before the insertion and, if the preceding opcode was ‘call’, we would add 5 to the line number (in Hex) to get the new line number for our first line of code. This will be shown in an example later.

.maxstack Opcode/Directive

One of the topics where I and the original author of the first whitepaper on this attack differ is the .maxstack directive.. This opcode is a little confusing by its name - as it is not the maximum number of bytes on the stack, nor the number of items. The .maxstack directive helps a tracking tool (like a debugger or profiler) keep track of X amount of objects (if you wanted good debuggable or profilable code, then you would add your new IL maxstack to the value of the victim code and set the total). However, I would not like my malicious code to be compatible with debugging, thank you very much. Leave this alone.

For your reference in any ideological front where you may need to explain yourself, I include this snippet from page 17 of ECMA Partition III Specification:

“[Note: Maxstack is related to analysis of the program, not to the size of the stack at runtime. It does not specify

the maximum size in bytes of a stack frame, but rather the number of items that shall be tracked by an analysis

tool. end note]

[Rationale: By analyzing the CIL stream for any method, it is easy to determine how many items will be

pushed on the CIL Evaluation stack. However, specifying that maximum number ahead of time helps a CIL-tonative-

code compiler (especially a simple one that does only a single pass through the CIL stream) in allocating

internal data structures that model the stack and/or verification algorithm. end rationale]”

Like I said, if you don’t want easy debug analysis of your unfriendly code, leave this alone. If you want to build a debug/profiler enabled version, add your .maxstack value to the injection method’s .maxstack value.

How to Mate Your Code

Some functions are purely static - meaning that they instantiate no locals at all (you won’t need this info), such as in the example project’s Console.WriteLine(string) method. If this is the case with your victim code, but your malicious code has a .locals directive – you must include that .locals directive on the calling code. There is more information regarding locals at the end of the tutorial.

Altering the Assembly

In order to alter the assembly we must take the following steps

1. Renumber the lines via the documentation

2. Fix and remember the locals init order, as well as the stlocals (if required)

The resultant, ready to mate code for doubling the writeline() function would look like the following:

.method public hidebysig static void WriteLine(string 'value') cil managed


.permissionset linkcheck

= {class 'System.Security.Permissions.HostProtectionAttribute, mscorlib, Version=, Culture=neutral, PublicKeyToken=b77a5c561934e089' = {property bool 'UI' = bool(true)}}

// Code size 12 (0xc)

.maxstack 8

IL_0000: call class System.IO.TextWriter System.Console::get_Out()

IL_0005: ldarg.0

IL_0006: callvirt instance void System.IO.TextWriter::WriteLine(string)

IL_000b: call class System.IO.TextWriter System.Console::get_Out()

IL_0010: ldarg.0

IL_0015: callvirt instance void System.IO.TextWriter::WriteLine(string)

IL_001b: ret

} // end of method Console::WriteLine

...... Next post will show you how to edit, compile, and move the assembly back into the GAC.