Slashdot Mirror


The 2015 Underhanded C Contest Has Begun

Xcott Craver writes: The 8th Underhanded C Contest is now underway. The goal of the Underhanded C Contest is to write C code that is as readable, clear, innocent and straightforward as possible, but which performs some malicious function that is not obvious from looking at the source code. This year's challenge is based on a real problem in joint development for nuclear treaty verification, and the prize is $1000.

52 comments

  1. not obvious from looking at the source code. by Anonymous Coward · · Score: 5, Funny

    So, pretty much any C program will be competitive here.

    1. Re:not obvious from looking at the source code. by Anonymous Coward · · Score: 0

      Heh, actually I would have it generate a perl script and then execute that script. Much more cryptic that way.

  2. Sponsered by Systemd by Anonymous Coward · · Score: 5, Funny

    Clearly this contest must be in someway related to Systemd but I find no mention in TFA

    1. Re:Sponsered by Systemd by Anonymous Coward · · Score: 1

      The relationship is pretty straightforward actually. Systemd was the winner of this prize 2 years ago.

  3. Wait, wait by JustAnotherOldGuy · · Score: 1

    Isn't all C++ underhanded?

    My C++ programmer buddies swear that the language was designed by a team of masochists who had a poor sense of humor and anger management issues.

    --
    Just cruising through this digital world at 33 1/3 rpm...
    1. Re:Wait, wait by Dutch+Gun · · Score: 2

      I'd argue that C++ has to be considered in two different cases, one for library writers and one for library users. Moreover, let's talk about modern C++ (C++14) rather than legacy C++, with all the cruft compatibility with C and older C++ version gives us.

      C++ is an incredibly complicated but unbelievably powerful language for writing libraries. It allows high-level abstraction that compiles down to code every bit as efficient as the much more dangerous equivalent C code. A lot of the really complicated parts of C++ are actually intended for library writers, where advanced techniques can make the libraries easier to use, safer, and more efficient at the cost of code complexity. Many programmers believe that they need to master all these subtle and tricky parts of the language in order to properly use C++, but I don't believe that to be the case at all.

      The other aspect of C++ is a programmer who mostly *uses* libraries to build new functionality (application-level programming). This sort of C++ is actually fairly straightforward, so long as you have a reasonable knowledge level of the language. That is, you can write classes properly (rule of three, now extended to rule of four), understand scope and resource management (RAII), simple rules for keeping classes exception safe (like the copy/swap idiom), and understand how to make use of the newest features like smart pointers. Modern C++ code can and should be written in such a way that it's impossible to stomp on memory you don't own, and difficult to accidentally leak memory or other resources, and all without losing any significant efficiency compared to C.

      I'd say the biggest problem C++ has is that many programmers simply don't understand how to properly break things up into discrete classes and tend to overuse inheritance instead of composition as a means of building complex functionality. As such, you often tend to see nightmarish class hierarchies filled will massive classes that perform dozens and dozens of completely discrete functions, instead of classes composed of smaller classes, each with a well-defined and testable set of operators and behavior. Moreover, you see many programmers combining this with the most dangerous of C behaviors, such as passing around raw object pointers or memory buffers, especially in older legacy code. It's no wonder C++ has a reputation of being a difficult language.

      I'd never argue that C++ is an *easy* language to use. In fact, it's pretty easy to write really horrible, unmanageable C++ code, which I think is probably *worse* than bad C code in many ways. However, *good* C++ is far more manageable and safer than the equivalent C code while being every bit as run-time efficient.

      --
      Irony: Agile development has too much intertia to be abandoned now.
  4. Start with this Password Verification Function by mykepredko · · Score: 4, Interesting

    I'm trying to remember where I first saw this function (I think it's a pretty common example for security coding seminars):

    int passwordCompare(char* enteredPassword, char* validPassword) {
    int i;

            for (i = 0; (len(enteredPassword) > i) && (enteredPassword[i] == validPassword[i]; ++i) {
            }

            if (len(enteredPassword) == i) {
                    return -1; /* true */
            }
            else {
                    return 0; /* false */
            }
    }

    but, I would imagine that it would qualify as an example for the contest. I don't think it was originally designed to be malicious, but more of a coding error.

    I would expect most of the entries in the contest would be of this variety, something that a (new) coder has put in that works for basic test cases, but has a serious flaw...

    1. Re:Start with this Password Verification Function by alvinrod · · Score: 5, Interesting

      Go look at some of the winners from previous years. Some of the solutions are on such a diabolical level that they might take days or weeks to fully track down and understand and are so convoluted that no one could possibly think it was intentional.

      Last year's winner is a rather good example.

    2. Re:Start with this Password Verification Function by Anonymous Coward · · Score: 0

      Since the length of the entered password is the problem, I guess the missing ")" is not the trick.

    3. Re:Start with this Password Verification Function by Anonymous Coward · · Score: 0

      error: unresolved external symbol 'len' ....

    4. Re:Start with this Password Verification Function by sexconker · · Score: 0

      Lots of things are a problem in that example.

      Consider a valid password of "abc" and an entered password of "a".
      Consider a blank entered password.

      That ridiculous for loop construction needs to go.

    5. Re:Start with this Password Verification Function by dotancohen · · Score: 4, Funny

      I'm trying to remember where I first saw this function (I think it's a pretty common example for security coding seminars):

      int passwordCompare(char* enteredPassword, char* validPassword) {

      Hey, that's the routine that checks the password on my luggage!

      --
      It is dangerous to be right when the government is wrong.
    6. Re:Start with this Password Verification Function by Anonymous Coward · · Score: 0

      I'm trying to remember where I first saw this function (I think it's a pretty common example for security coding seminars):

      int passwordCompare(char* enteredPassword, char* validPassword) {
      int i;

              for (i = 0; (len(enteredPassword) > i) && (enteredPassword[i] == validPassword[i]; ++i) {

              }

              if (len(enteredPassword) == i) {

                      return -1; /* true */

              }

              else {

                      return 0; /* false */

              }
      }

      but, I would imagine that it would qualify as an example for the contest. I don't think it was originally designed to be malicious, but more of a coding error.

      I would expect most of the entries in the contest would be of this variety, something that a (new) coder has put in that works for basic test cases, but has a serious flaw...

      Things wrong with that code:

      Any truncated version of the real password (including empty) passes. It contains a timing side channel. Verifyer should not save the password (use some nice protocol like SRP, or at least an expensive hash, like Bcrypt).

      Oh, and an input string of sufficient length can overflow the signed i but not the size_t strlen (assuming len meant strlen) returns producing out of bounds memory reads (Usually int is big enough you can't but both of the char*s in memory to do this though, but it should really use size_t for i). This int overflow is undefined behavior in C, so it could do anything.

      Of course that likely doesn't matter due to the N^2 runtime and thus potential DOS bug.

      If you want an easy (but perhaps overkill) timing side channel detection approach: this code contains a secret data dependent memory accesses, and branches (either of those should be considered bad in an online verification scenario).

    7. Re:Start with this Password Verification Function by Anonymous Coward · · Score: 0

      Can someone please add annotations to this snippet for the non-coders here?

    8. Re:Start with this Password Verification Function by danceswithtrees · · Score: 1

      Serious question here. I was wondering whether C lends itself to obfuscation of undesired/malicious behavior or whether it is just the preferred language of people able to dream up such deviousness. Would someone with enough python-fu be able to pull this off or would the deception/error be easier to detect by the average coder? i.e. would an underhanded python contest be feasible or would the deception to readily apparent (or at least more apparent)?

    9. Re:Start with this Password Verification Function by fredan · · Score: 1

      int passwordCompare(char* enteredPassword, size_t enteredPassword_len, char* validPassword,  size_t* validPassword_len) {

      if (enteredPassword_len != validPassword_len) {
      return 0;
      }

      if (timeingsafe_memcmp(enteredPassword, validPassword, validPassword_len) == 0) {
      return -1;
      }
      return 0;
      }

    10. Re:Start with this Password Verification Function by nickweller · · Score: 1

      So, i is always equal to the length of the entered password?

    11. Re:Start with this Password Verification Function by istartedi · · Score: 1

      It took me a minute or two to realize you aren't checking the length of both strings. The real red flag for me was that it doesn't use the standard library's comparison function.

      --
      For all intensive purposes, "whom" is no longer a word. That begs the question, "who cares"?
    12. Re:Start with this Password Verification Function by Anonymous Coward · · Score: 0

      You can write underhanded stuff in any language. The thing with C is that it is so powerful and can touch almost anything that it is easier to do.

    13. Re:Start with this Password Verification Function by ultranova · · Score: 1

      Would someone with enough python-fu be able to pull this off or would the deception/error be easier to detect by the average coder?

      Isn't the main reason Python code is so slow that it's nigh impossible to prove anything about it, even to a computer?

      --

      Forget magic. Any technology distinguishable from divine power is insufficiently advanced.

    14. Re:Start with this Password Verification Function by Anonymous Coward · · Score: 0

      So the bug is in validPassword_len being a pointer?

      Pray tell, if that compiles, what the security implications are. I'd figure either the first if always returns 0 or things work out just as without the bug.

    15. Re:Start with this Password Verification Function by wonkey_monkey · · Score: 1

      for (i = 0; (len(enteredPassword) > i) && (enteredPassword[i] == validPassword[i]; ++i) {

      Did you miss a ) out of there somewhere?

      How are we supposed to spot the bug in your bug-riddled code? ;)

      --
      systemd is Roko's Basilisk.
    16. Re:Start with this Password Verification Function by wonkey_monkey · · Score: 1

      Wouldn't you get a compiler error (or at least a warning) about trying compare a size_t* with a size_t? And if you didn't, the trick would still rely on the caller passing the pointer rather than the value... wouldn't it?

      --
      systemd is Roko's Basilisk.
    17. Re:Start with this Password Verification Function by Anonymous Coward · · Score: 0

      i.e. would an underhanded python contest be feasible or would the deception to readily apparent (or at least more apparent)?

      Underhanded python certainly is feasible. Especially with the way python deals with white-space, but in general, the higher level the language the easier it is to write something with hidden side-effects.
      Underhanded assembly on the other hand is pretty hard. Unless you resort to self modifying code and abuse that separate instruction and data cache will mess things up it is very hard to hide functionality in assembly. (But sometime entries in the underhanded competition uses little known quirks of library functions, if called those are viable in any language you can call them from.)

    18. Re:Start with this Password Verification Function by Dutch+Gun · · Score: 1

      I'd guess the reason C is used is because it's still the programming language of choice for operating systems and security libraries. Nearly every commonly-used OS is written in C, and as such, it's the most relevant language to demonstrate such techniques in.

      It also happens to be a somewhat low-level language that allows for all sorts of crazy tricks and techniques, especially once you add in the preprocessor. So, win-win, as far as this contest is concerned.

      --
      Irony: Agile development has too much intertia to be abandoned now.
    19. Re:Start with this Password Verification Function by Anonymous Coward · · Score: 0

      Not using the standard library's compare function is not, itself, a warning sign as it may leak data. The two main ones are memory ones where, for example, the size changes depending on how far the comparison and time, where the comparison function short circuits. An example of the latter is:

      for x in range(len(password)):
              if password[x] != input[x]:
                      return False
      return True

      doesn't look like much but time 100 rounds for each character and you can figure out which is correct at that place.

    20. Re:Start with this Password Verification Function by Anonymous Coward · · Score: 0

      That would stand out like a sore thumb. Not for the coding error (it took me three tries) but for the doofus-level security design error visible from the header alone.

    21. Re:Start with this Password Verification Function by Anonymous Coward · · Score: 0

      Strange that your reply was modded down...

      That is a ridiculous for() loop. Reminds me of the code I saw when reading the check-in that created the heartbleed vulnerability. I felt the same way about it: As soon as someone saw it, they should have rejected the commit outright. Unfortunately I imagine what actually happened was that they found analysing exactly what the code did to be too difficult, and so decided to accept it merely based upon the reputation of whomever submitted it.

      I think that happens a lot, as people consider it an insult to their programming skills if they can't understand someone else's code, and so they don't want to admit that they can't. Indeed, I couldn't figure out the above code either, at least not in the time frame I was willing to look at it. However, I certainly knew it was awful code and never would have accepted it as a patch to any software I've written, regardless of whether it worked correctly.

      It isn't sufficient that code works. It also needs to be written as straightforwardly as possible, so that it is as readily apparent as possible that the code is correct. It isn't always possible to write obviously-correct code, but one can certainly compare two strings in an obviously-correct manner, and that for() loop is hideously complex for such a simple operation.

    22. Re:Start with this Password Verification Function by Anonymous Coward · · Score: 0

      I'd just enter nothing, eg. no chars.

      0 == 0

    23. Re:Start with this Password Verification Function by Anonymous Coward · · Score: 1

      The for loop counts the number of characters from the start that match. I.e., with entered password abc and actual password abd, you would have i=2.

      Then the condition tests if the number of matched characters is the length of the password. If all characters in the entered password match the corresponding characters in the stored password, the function returns true, otherwise it returns false.

      The critical flaw is that it only compares up to the length of the entered password, so an empty password passes.

    24. Re:Start with this Password Verification Function by Anonymous Coward · · Score: 0

      But that's only half the problem. If you enter a password *longer* than the valid one, you can access memory past the end of the validPassword array. If the password check program is running as an elevator user, this could potentially be used for privilege escalation beyond even the highest privileged account the function is checking against.

  5. Man I swear I've written code by kungfuj35u5 · · Score: 1

    that fits this bill. Code that I swore up and down covered all corner cases for input but with enough fuzzing could be coaxed into crashing.

  6. Re:Linux by Anonymous Coward · · Score: 1

    Nah, it shows how everything is probably loaded with backdoors, including your compiler, bios, firmware, and your operating system.

  7. C and C++ differ dramatically in complexity by Anonymous Coward · · Score: 5, Interesting

    Isn't all C++ underhanded?

    This contest concerns underhanded C, not C++. There would be little point in an underhanded C++ contest.

    C is a trivially simple language, with a very small syntax and a very narrow set of semantics. As a result, you have to work pretty hard to make ordinary C contain hidden functionality --- usually this requires abusing the C preprocessor, because the C grammar itself doesn't provide much room for hiding things.

    C++ is at the other end of the complexity scale, being the language with the largest syntax and the most extremely complex semantics of any programming language on the planet. It took that crown from Ada many decades ago, and it hasn't stopped growing since.

    Because of C++'s huge size in every respect, C++ programmers tend to develop their own preferred subsets of the language, and they stick with that subset throughout their lives. There's nothing wrong with that (indeed, it's probably the only way of working with C++), but it has the consequence that one person's clear C++ is another person's incomprehensible C++.

    That makes writing underhanded C++ a rather pointless exercise.

    1. Re:C and C++ differ dramatically in complexity by Anonymous Coward · · Score: 0

      usually this requires abusing the C preprocessor, because the C grammar itself doesn't provide much room for hiding things.

      Or disguise it as one of the many mistakes enabled by C. Some of the winners had been commented with how common a specific error used to add the hidden functionality was, allowing the authors some plausible deniability. The C preprocessor with its multiple evaluations, bad interaction with operator precedence, etc. is joined by a complete lack of type and memory safety in the C standard library.

      but it has the consequence that one person's clear C++ is another person's incomprehensible C++.

      On the positive side, a lot of code that passes through the underhanded C contest just fine would raise eyebrows at an underhanded C++ contest.

    2. Re:C and C++ differ dramatically in complexity by epine · · Score: 5, Insightful

      C is a trivially simple language

      You're crazy.

      Back in the eighties when I was primarily a C programmer, I spent years mastering the art of writing portable C code. Our main application was required to compile under both the Microsoft and the Watcom compiler, and under the Watcom compiler we targeted both MSDOS and QNX. This was a royal PITA at times. The worst case I recall is that Microsoft had a bug in their type deduction logic for expressions that mixed signed and unsigned values. In actual fact, the Microsoft code generator used the correct rules, but the Microsoft diagnostic routine in the parser did not, causing it to issue "type conversion" warnings opposite to its own internal behaviour. Just imagine how that gave us a bad case of group-consciousness head spin until we tracked down the underlying cause.

      It's terribly hard in C to defend yourself against certain kinds of accidental errors, which is one of my original reasons for moving to C++. My well-developed C programming subset (oh yes, I had a subset) was even more robust in C++. For example, in modern C++ there's much less justification for writing complex expressions using #define. Modern C++ programmers largely restrict the use of the C++ preprocessor for implementing a Turing-complete language at compile time.

      Is the C99 preprocessor Turing complete?

      Actually, I lied. That harmless looking C preprocessor from the dusty depths of time is but a C-hair short of being Turing complete at compile time. The smallest fiddle in the specification of token pasting might get you there.

      Concerning underhandedness, the Karen Pease PIU winner would not survive having __isleap() recoded from a macro to a C++ inline function. Many of the other examples abuse the #define mechanism for encoding object lengths, rather than having the objects maintain their own lengths, such as any STL container does.

      What you can foist in the unwary if you're off-scale malicious in C++ is off-scale high (it is, after all, a superset of C itself).

      On the other end of the scale, if you use C++ abstractions to do good rather than evil, the never-ending refinement of the C++ language takes you to a better place, not a worse place.

      Elements of Modern C++ Style

      I'm not overly enamoured of Great Man theory, and likewise I'm not greatly enamoured of sanitary-conception language design, in which all the sins of the past are taken behind the woodshed and put straight en masse.

      Co-existence with our dirty origins is a simple fact of human biology. It isn't true that every complexity of human evolution is automatically a turn for the worse (as you seem to imply about accrued complexity in programming language design).

      The truth of the matter is that C++ used wisely can be a clean and empowering programming language, for those of us able and willing to pay the price of admission.

      Whether it's reasonable to pay that price given the many other choices available now is another question. In my case, I had already paid half the price in my first professional decade as a C programmer, after stripping away the illusion that C is simple language.

      I'm pretty much agnostic at this point about whether an ambitious young programmer should bother learning C++ or not, unless it happens that C++ is the only vehicle that will take you where you want to go (high abstraction level co-existing with raw hardware performance).

      Too many people sit there in a state of contempt fundamentally saying "if C++ is the only viable solution, then I want a simpler problem to solve!"

      Well, go to it. Fill your boots. But don't sit there and sneer at the brave souls who make the opposite choice.

    3. Re:C and C++ differ dramatically in complexity by Anonymous Coward · · Score: 0

      I enjoy both C and C++.

      I program in COBOL and assembly at work though :-)

    4. Re:C and C++ differ dramatically in complexity by Anonymous Coward · · Score: 0

      Whether it's reasonable to pay that price given the many other choices available now is another question.

      Given the Stupid Preening Court's decision on Oracle's API, C++ is absolutely worth the price, since the standard library API isn't subject to some asshat CEO wanting access to the wallets of everybody using the language.

    5. Re:C and C++ differ dramatically in complexity by peetm · · Score: 1

      ...but it has the consequence that one person's clear C++ is another person's incomprehensible C++

      That makes writing underhanded C++ a rather pointless exercise.

      No it doesn't - it's good for job security because no one else knows what your code does.

      --
      @peetm
  8. Example for screwy logic contest .. by nickweller · · Score: 1

    @anon: 'This contest shows how Linux is probably loaded with backdoors.'

    And closed source is free of backdoors as we can never see the source code?

  9. Underhanded prize by Anonymous Coward · · Score: 0

    If this were the underhanded Perl contest, I would trust that $1000 prize to be woth ten Benjamins.

  10. The winner by fluffernutter · · Score: 1

    Let us all set back and appreciate the scariest bit of C code ever written:

    main( ) {
    printf("hello, world");
    }

    --
    Laws are rules for the court, but merely a bottom bar to hit for life. Think beyond laws in your actions always.
    1. Re:The winner by jittles · · Score: 1

      Let us all set back and appreciate the scariest bit of C code ever written: main( ) { printf("hello, world"); }

      It's scary because you used the same formatting they use in K&R. The same formatting that people have used for dozens of years as if they need to save white space because they're publishing a book! It drives me nuts when people put the { on the end of the line. They only did that in books to save space!

    2. Re:The winner by Anonymous Coward · · Score: 0

      How dare you question the Word of God!?
      God descended upon Ritchie, peace be upon him, and gave him the rules of proper syntax.
      The Lord said to him: "Thou shalt place thine opening brackets in the last line of thine block-containing statement before thenceforth writing the block contents. Thou shalt never separate the statement and the bracket with a newline. That would be sinful."
      As Ritchie, peace be upon him, was only able to type words containing no vowels, he faithfully recited the Word to Kernighan and thus was the Book written.
      The Wrath of God shall fall upon infidels.

  11. Only a grand? by Ydna · · Score: 1

    Only US$1,000.00? That's useless. For those who study the history of code (in any klanguage, but especially C [or microcode]), this could be a meaningful challenge. But only if we're talking six figures. At least the really smart people I've been blessed to associate with are worth it.

    --

    "The great thing about multitasking is that several things can go wrong at once." -me

    1. Re:Only a grand? by Anonymous Coward · · Score: 0

      dat self flagellation doe