diff --git a/Makefile b/Makefile index bef9f96..19afd28 100644 --- a/Makefile +++ b/Makefile @@ -19,4 +19,4 @@ clean: packages-clean scrub: clean rm -rf $(CACHE) -include packages/packages.mk +-include */*.mk diff --git a/doc/2010-10-NMT/email1.txt b/doc/2010-10-NMT/email1.txt index 2685869..dee8079 100644 --- a/doc/2010-10-NMT/email1.txt +++ b/doc/2010-10-NMT/email1.txt @@ -11,48 +11,61 @@ There are 5 tokens hidden in this message. Can you find them all? --eJwryC8uSS0qtqpIzc1P1i3OT86vAABObgfA Content-type: text/plain; charset=UTF-8 -Are you ready for CTF? +CTF starts TOMORROW! Do you have sufficient stores of Mountain Dew? -The teams are in and it looks like this year's CTF is going to be about -double the size of last year. I've posted teams at -. +This is CMU's first ever CTF, so please be ready for a couple of +hiccups. Likewise, we expect you to be totally lost for a while, as you +get your bearings. While we tried to cover everything in the +registration web page, here are some points worth repeating: -If you came last year, there are some changes in store for you. I've -done away with the weird boxes at each table, so there's no need to -bring a monitor or keyboard. What you really need to be a sysadmin this -year is netcat and nmap. We will *not* provide an Internet connection, -so figure out now how you're going to get onto the Internet (you will -need it). +Your machine really ought to have netcat and nmap, and whatever +programming language(s) you prefer. An Ubuntu live CD has, at past +contests, not been sufficient. It's also a good idea to make sure your +computer works before you show up. Time is precious, don't spend yours +installing an operating system. + +We will have a switch at each table with gobs of ports, but you should +bring your own network cable. We will *not* provide an Internet +connection, so figure out now how you're going to get onto the Internet +(you will need it). If you have any questions, or would just like to hang out and shoot the breeze, feel free to hop on IRC (server woozle.org, channel #ctf). -I hope you all have as much fun playing this as I've had building it! +We hope you have as much fun playing this as we're going to have +watching you work! -zephyr +The Dirtbags + +PS: are you aware of how much data can be hidden in a single email? --eJwryC8uSS0qtqpIzc1P1i3OT86vAABObgfA Content-type: text/html; charset=UTF-8 -

Are you ready for CTF?

+

CTF starts TOMORROW! Do you have sufficient stores of Mountain Dew?

-

The teams are in and it looks like this year's CTF is going to be -about double the size of last year. I've posted teams at -http://dirtbags.net/ctf.

+

This is CMU's first ever CTF, so please be ready for a couple of +hiccups. Likewise, we expect you to be totally lost for a while, as you +get your bearings. While we tried to cover everything in the +registration web page, here are some points worth repeating:

-

If you came last year, there are some changes in store for you. I've -done away with the weird boxes at each table, so there's no need to -bring a monitor or keyboard. What you really need to be a sysadmin this -year is netcat and nmap. We will not provide an -Internet connection, so figure out now how you're going to get onto the -Internet (you will need it).

+

Your machine really ought to have netcat and nmap, and whatever +programming language(s) you prefer. An Ubuntu live CD has, at past +contests, not been sufficient. It's also a good idea to make sure your +computer works before you show up. Time is precious, don't spend yours +installing an operating system.

-

If you have any questions, or would just like to hang out and shoot -the breeze, feel free to -hop on IRC (server woozle.org, channel #ctf).

+

We will have a switch at each table with gobs of ports, but you should +bring your own network cable. We will *not* provide an Internet +connection, so figure out now how you're going to get onto the Internet +(you will need it).

-

I hope you all have as much fun playing this as I've had building it!

+

If you have any questions, or would just like to hang out and shoot the +breeze, feel free to hop on IRC (server woozle.org, channel #ctf).

-

zephyr

+

We hope you have as much fun playing this as we're going to have +watching you work!

+ +

The Dirtbags

--eJwryC8uSS0qtqpIzc1P1i3OT86vAABObgfA-- cbfgref:krzbp-fbpbk diff --git a/doc/2011-01-CMU/email1.txt b/doc/2011-01-CMU/email1.txt new file mode 100644 index 0000000..dee8079 --- /dev/null +++ b/doc/2011-01-CMU/email1.txt @@ -0,0 +1,71 @@ +From: The Dirtbags +To: RECIP +Subject: WIN BIG AT CAPTURE THE FLAG!!! +Message-ID: +MIME-Version: 1.0 +Content-type: multipart/alternative; boundary=eJwryC8uSS0qtqpIzc1P1i3OT86vAABObgfA +X-Face: '8$#2%$m/.;29z5"5"/ + +There are 5 tokens hidden in this message. Can you find them all? + +--eJwryC8uSS0qtqpIzc1P1i3OT86vAABObgfA +Content-type: text/plain; charset=UTF-8 + +CTF starts TOMORROW! Do you have sufficient stores of Mountain Dew? + +This is CMU's first ever CTF, so please be ready for a couple of +hiccups. Likewise, we expect you to be totally lost for a while, as you +get your bearings. While we tried to cover everything in the +registration web page, here are some points worth repeating: + +Your machine really ought to have netcat and nmap, and whatever +programming language(s) you prefer. An Ubuntu live CD has, at past +contests, not been sufficient. It's also a good idea to make sure your +computer works before you show up. Time is precious, don't spend yours +installing an operating system. + +We will have a switch at each table with gobs of ports, but you should +bring your own network cable. We will *not* provide an Internet +connection, so figure out now how you're going to get onto the Internet +(you will need it). + +If you have any questions, or would just like to hang out and shoot the +breeze, feel free to hop on IRC (server woozle.org, channel #ctf). + +We hope you have as much fun playing this as we're going to have +watching you work! + +The Dirtbags + +PS: are you aware of how much data can be hidden in a single email? +--eJwryC8uSS0qtqpIzc1P1i3OT86vAABObgfA +Content-type: text/html; charset=UTF-8 + +

CTF starts TOMORROW! Do you have sufficient stores of Mountain Dew?

+ +

This is CMU's first ever CTF, so please be ready for a couple of +hiccups. Likewise, we expect you to be totally lost for a while, as you +get your bearings. While we tried to cover everything in the +registration web page, here are some points worth repeating:

+ +

Your machine really ought to have netcat and nmap, and whatever +programming language(s) you prefer. An Ubuntu live CD has, at past +contests, not been sufficient. It's also a good idea to make sure your +computer works before you show up. Time is precious, don't spend yours +installing an operating system.

+ +

We will have a switch at each table with gobs of ports, but you should +bring your own network cable. We will *not* provide an Internet +connection, so figure out now how you're going to get onto the Internet +(you will need it).

+ +

If you have any questions, or would just like to hang out and shoot the +breeze, feel free to hop on IRC (server woozle.org, channel #ctf).

+ +

We hope you have as much fun playing this as we're going to have +watching you work!

+ +

The Dirtbags

+--eJwryC8uSS0qtqpIzc1P1i3OT86vAABObgfA-- + +cbfgref:krzbp-fbpbk diff --git a/doc/2011-01-CMU/thanks.png b/doc/2011-01-CMU/thanks.png new file mode 100644 index 0000000..55e8427 Binary files /dev/null and b/doc/2011-01-CMU/thanks.png differ diff --git a/doc/2011-01-CMU/thanks/blob b/doc/2011-01-CMU/thanks/blob new file mode 100644 index 0000000..61d84fd Binary files /dev/null and b/doc/2011-01-CMU/thanks/blob differ diff --git a/doc/2011-01-CMU/thanks/t.png b/doc/2011-01-CMU/thanks/t.png new file mode 100644 index 0000000..55e8427 Binary files /dev/null and b/doc/2011-01-CMU/thanks/t.png differ diff --git a/doc/2011-01-CMU/thanks/thanks b/doc/2011-01-CMU/thanks/thanks new file mode 100755 index 0000000..0becabf Binary files /dev/null and b/doc/2011-01-CMU/thanks/thanks differ diff --git a/doc/2011-01-CMU/thanks/thanks.c b/doc/2011-01-CMU/thanks/thanks.c new file mode 100644 index 0000000..fb1ee64 --- /dev/null +++ b/doc/2011-01-CMU/thanks/thanks.c @@ -0,0 +1,19 @@ +char *t = ( +"Thank you for helping make Capture The Flag a success! We couldn't" +"have done it without you." + +"As our way of saying thank you, we humbly offer this image" +"proclaiming you to be a cool person. Please feel free to print" +"off a copy of this image and post it in your window, over your" +"pannier, on your forehead, or wherever else you feel is appropriate." + +"Sincerely," + +" The Dirtbags" +); + +#include +int main(){char*p=t;while(1){int +c=getchar();if(EOF==c)break; +putchar(c^*p);if(!*++p)p=t;}return +0;} diff --git a/doc/2011-01-CMU/thanks/thanks.png b/doc/2011-01-CMU/thanks/thanks.png new file mode 100644 index 0000000..55e8427 Binary files /dev/null and b/doc/2011-01-CMU/thanks/thanks.png differ diff --git a/doc/2011-01-CMU/thanks/thanks.svg b/doc/2011-01-CMU/thanks/thanks.svg new file mode 100644 index 0000000..0fd412c --- /dev/null +++ b/doc/2011-01-CMU/thanks/thanks.svg @@ -0,0 +1,371 @@ + + + + + + + + + + + image/svg+xml + + + + + + + Capture the Flag 2011 + + at + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Central Michigan University + happened with my helpbecause I am a cool person! + + + + + right on! + + + diff --git a/doc/2011-TF3/categories.txt b/doc/2011-TF3/categories.txt new file mode 100644 index 0000000..cb5401b --- /dev/null +++ b/doc/2011-TF3/categories.txt @@ -0,0 +1,15 @@ +TF3 Categories +============== + +Last year we ran: + + bletchley, compaq, crypto, forensics, hackme, hispaniola, net-re, + sequence, skynet, survey, webapp, tanks, badmath, kevin + + +This year we have: + + basemath, bletchley, codebreaking, compaq, crypto, forensics, + hackme, logger, net-re, octopus, printf, pwnables, sequence, skynet, + steg, tanks, webapp + diff --git a/doc/interest.txt b/doc/interest.txt new file mode 100644 index 0000000..f06479b --- /dev/null +++ b/doc/interest.txt @@ -0,0 +1 @@ +andrew.hay@afit.edu diff --git a/doc/token-categories.txt b/doc/token-categories.txt new file mode 100644 index 0000000..f5ebcb8 --- /dev/null +++ b/doc/token-categories.txt @@ -0,0 +1,176 @@ +LANL CTF Token-Based Categories +=============================== + +LANL's CTF contest allows for easy addition of new modules which can use +"tokens". A token is a character string worth one point in the contest. +A point may only be claimed once per team, but multiple teams can claim +the same token and each will get a point. Tokens look like this: + + example:xylep-donut-nanox + +Tokens are issued by the token server using the tokencli program at the +end of this document. They can also be issued before the beginning of a +contest. If your category allows it, it will be much easier for you to +simply request a number of tokens before the contest begins, and +hard-code them into your category. + +You will want to arrange that participants get a token after having +completed some sort of task. In existing categories, tokens are +frequently what lie beneath some trail of hacking. For instance, one +program provides a token when the proper printf formatting string is +provided. Another embeds five tokens into log messages using different +encodings. + +Any machine that you connect to our network will get a wired connection +and should claim a static IP address on the 10.0.2.0/24 network. While +it's unlikely you'll conflict with anyone else, be prepared to +reconfigure it with a new IP on the morning of the event. + +If you plan to request tokens, please do so at least 2 weeks before the +start of the event. I will need to know what you'd like your category +to be called, and how many tokens you'd like. It's not a problem if you +don't use all the tokens you request. + +Remember that this is a security contest, and contestants will be far +more engaged with your category if they have to do real work to get the +tokens. For example, a vendor might be tempted to leave tokens lying +around in configuration boxes to reward people who explore its rich +configurability, but this would probably result in people clicking +through the UI as quickly as possible looking only for tokens. Far +better would be to have the tokens lying under the products +functionality somewhere, forcing contestants to interact with the +product like they would in their day to day work after having purchased +it. A Snort category, for instance, would do well to have tokens within +packet captures which triggered alarms. + +I can't stress that last point enough: constestants have been known to +spend over 2 hours on a single problem. Don't be afraid to really +challenge them. + + + + + + +/* tokencli.c - LANL CTF token client +Author: Neale Pickett + +This program requires an arc4 implementation, email me if you can't find +one you like. + +This also requires a shared 128-bit key. I need the key before you can +start requesting tokens from the server :) + + +This software has been authored by an employee or employees of Los +Alamos National Security, LLC, operator of the Los Alamos National +Laboratory (LANL) under Contract No. DE-AC52-06NA25396 with the +U.S. Department of Energy. The U.S. Government has rights to use, +reproduce, and distribute this software. The public may copy, +distribute, prepare derivative works and publicly display this software +without charge, provided that this Notice and any statement of +authorship are reproduced on all copies. Neither the Government nor +LANS makes any warranty, express or implied, or assumes any liability or +responsibility for the use of this software. If software is modified to +produce derivative works, such modified software should be clearly +marked, so as not to confuse it with the version available from LANL. +*/ + + +#include +#include +#include +#include +#include +#include +#include +#include "arc4.h" + +/* I don't feel compelled to put all the TCP client code in here + * when it's so simple to run this with netcat or ucspi. Plus, using + * stdin and stdout makes it simpler to test. + */ + +int +read_key(char *filename, uint8_t *key, size_t *keylen) +{ + int fd = open(filename, O_RDONLY); + int len; + + if (-1 == fd) { + perror("open"); + return EX_NOINPUT; + } + + len = read(fd, key, *keylen); + if (-1 == len) { + perror("read"); + return EX_NOINPUT; + } + *keylen = (size_t)len; + + return 0; +} + +int +main(int argc, char *argv[]) { + uint8_t skey[200]; + size_t skeylen = sizeof(skey); + char token[200]; + size_t tokenlen; + int ret; + + if (argc != 3) { + fprintf(stderr, "Usage: %s SERVICE SERVICEKEY 3>TOKENFILE\n", argv[0]); + fprintf(stderr, "\n"); + fprintf(stderr, "SERVICEKEY is a filename.\n"); + fprintf(stderr, "Server chatter happens over stdin and stdout.\n"); + fprintf(stderr, "Tokens are written to file descriptor 3.\n"); + fprintf(stderr, "\n"); + fprintf(stderr, "To run with netcat:\n"); + fprintf(stderr, " nc 10.0.0.2 1 -e tokencli cat cat.key 3> tokenfile\n"); + return EX_USAGE; + } + + /* read in keys */ + ret = read_key(argv[2], skey, &skeylen); + if (0 != ret) return ret; + + /* write service name */ + write(1, argv[1], strlen(argv[1])); + + /* read nonce, send back encrypted version */ + { + uint8_t nonce[80]; + int noncelen; + + noncelen = read(0, nonce, sizeof(nonce)); + if (0 >= noncelen) { + perror("read"); + return EX_IOERR; + } + arc4_crypt_buffer(skey, skeylen, nonce, (size_t)noncelen); + write(1, nonce, (size_t)noncelen); + } + + /* read token */ + { + int len; + + len = read(0, token, sizeof(token)); + if (0 >= len) { + perror("read"); + return EX_IOERR; + } + tokenlen = (size_t)len; + } + + /* decrypt it */ + arc4_crypt_buffer(skey, skeylen, (uint8_t *)token, tokenlen); + + /* write it to fd 3 */ + write(3, token, tokenlen); + + return 0; +} + diff --git a/doc/writing-puzzles.txt b/doc/writing-puzzles.txt new file mode 100644 index 0000000..77b2975 --- /dev/null +++ b/doc/writing-puzzles.txt @@ -0,0 +1,163 @@ +How to create puzzle categories +=============================== + +The contest has multiple "puzzle" categories. Each category contains a +collection of thematically-related puzzles with increasing point +values. This document will guide you through the process of creating a +new category. It's up to you to make challenging puzzles, though :) + +Since Unix commands are plain text, I'll be using the Unix commands to +illustrate steps. These are simple commands that should be easy to +translate to a GUI. + + +Step 1: Establish a progression +------------------------------- + +Before you do anything else, you should sit down with a pen and paper, +and plan out how you'd like contestants to progress through your +category. This contest framework is set up to encourage a linear +progression through puzzles, while still allowing contestants to skip +over things they get stuck on. + +The net-re category, for instance, features full tutorial pages with +simple "end of chapter" type questions for point values 1-8. Point +values 10-99 apply the skills learned in the tutorial against +increasingly challenging problems, point values 100-999 increasingly +approach real-world challenges which use the skills, and point values +1000+ are either culled or inspired by actual net-re tasks performed by +experts in the field. + +The crypto category uses the previous answers key as part of the +solution process for each point value. + +Ideally, your category will work standalone for novices, while allowing +experts to quickly answer the training questions and progress to real +challenges. Remember that some events don't have a class portion, and +even the ones that do have students who prefer to spend the contest time +reviewing the exact same problems they did in the class. + +Remember, it's easy to make incredibly challenging puzzles, and you will +probably have a lot of ideas about how to do this. What's harder is to +make simple puzzles that teach. It can be helpful to imagine a student +with a basic skill set. Write your first puzzle for this student to +introduce them to the topic and get them thinking about things you +believe are important. Guide that student through your tutorial +puzzles, until they emerge ready to tackle some non-tutorial problems. +As they gain confidence, keep them on their toes with new challenges. +Remember to only introduce one new concept for each puzzle! + +Past a certain point, feel free to throw in the killer tricky puzzles +you're just dying to create! + + + +Step 2: Establish point values +------------------------------ + +Each of your steps needs a point value. Each point value must be +unique: you may not have two 5-point puzzles. + +Point values should roughly reflect how difficult a problem is to solve. +It's not terribly important that a 200-point puzzle be ten times harder +than a 20-point puzzle, but it is crucial that a 25-point puzzle be +roughly as difficult as a 20-point puzzle. Poorly-weighted puzzles has +been the main reason students lose interest. + + + +Step 3: Set up your puzzle structure +------------------------------------ + +The best way to get puzzles to me is in a zip file of an entire +directory. Let's say you are going to create a "sandwich" category. +Your first step will be to make a "sandwich" directory somewhere. + + $ mkdir sandwich + $ cd sandwich + $ + +Within your category directory, create subdirectories for each point +value puzzle. In the "sandwich" category we have only 5, 10, and +100-point puzzles. + + $ mkdir 5 10 100 + $ + + +Step 4: Write puzzles +--------------------- + +Now that your skeleton is set up, you can begin to fill it in. In each +point-value subdirectory, there can be three special files, and as many +downloadable files as you like, in addition to CGI and any downloadable +but non-listed files you would like. + +Special files are: + +* index.mdwn: a plain text file formatted with + [markdown](http://daringfireball.net/projects/markdown/), displayed + before the list of normal files in the puzzle directory. +* key: a plain text file with acceptable answers, one per line. Answers + are matched exactly (ie. they are case-sensitive). +* summary: a single line explaining to contest organizers what's going + on in this puzzle. + +All remaining files, except those with filenames beginning with a comma +(","), are listed on the puzzle page for download. + +Any file ending with ".cgi" will be run as CGI. You can search the web +for how to write a CGI. Available languages are Python, Lua, and Bourne +Shell. + +Let's make our 5-point sandwich question! + + $ cd 5 + $ cat <index.mdwn + > Welcome to the Sandwich category! + > In this category you will learn how to make a tasty sandwich. + > The key ingredients in a sandwich are: bread, spread, and filling. + > When making a sandwich, you need to first put down one slice of bread, + > then apply any spreads, and finally add filling. Popular fillings + > include cheese, sprouts, and cold cuts. When you are done, apply + > another slice of bread on top, and optionally tie it together with + > a fancy toothpick. + > + > Now that you know the basics of sandwich-making, it's time for a + > question! How many slices of bread are in a sandwich? + > EOD + $ cat <key + > 2 + > TWO + > two + > EOD + $ echo "How many slices of bread in a sandwich" > summary + $ + +If you wanted to provide a PDF of various sandwiches, this would be the +time to add that too: + + $ cp /tmp/sandwich-types.pdf . + $ + +In a real category, you might provide an executable, hard drive image, +or some other kind of blob. + +No additional work is needed to have `sandwich-types.pdf` show up as a +download on the puzzle page. + + + +Step 5: Package it up +--------------------- + +After you've flushed out all your point-value directories, it's time to +wrap it up and send it in. Clean out any backup or temporary files you +or your editor might have written in the directories, and zip the sucker +up. + + $ cd ../.. + $ zip -r sandwich.zip sandwich/ + $ + +Now mail the zip file in, and you're all done! diff --git a/include/arc4.c b/include/arc4.c index 63306ad..8f13423 100644 --- a/include/arc4.c +++ b/include/arc4.c @@ -23,7 +23,7 @@ arc4_init(struct arc4_ctx *ctx, uint8_t const *key, size_t keylen) } uint8_t -arc4_pad(struct arc4_ctx *ctx) +arc4_out(struct arc4_ctx *ctx) { ctx->i = (ctx->i + 1) % 256; ctx->j = (ctx->j + ctx->S[ctx->i]) % 256; @@ -33,17 +33,17 @@ arc4_pad(struct arc4_ctx *ctx) void arc4_crypt(struct arc4_ctx *ctx, - uint8_t *obuf, uint8_t const *ibuf, size_t buflen) + uint8_t *obuf, const uint8_t *ibuf, size_t buflen) { size_t k; for (k = 0; k < buflen; k += 1) { - obuf[k] = ibuf[k] ^ arc4_pad(ctx); + obuf[k] = ibuf[k] ^ arc4_out(ctx); } } void -arc4_crypt_buffer(uint8_t const *key, size_t keylen, +arc4_crypt_buffer(const uint8_t *key, size_t keylen, uint8_t *buf, size_t buflen) { struct arc4_ctx ctx; @@ -51,3 +51,64 @@ arc4_crypt_buffer(uint8_t const *key, size_t keylen, arc4_init(&ctx, key, keylen); arc4_crypt(&ctx, buf, buf, buflen); } + + +#ifdef ARC4_MAIN + +#include +#include +#include + +int +main(int argc, char *argv[]) +{ + struct arc4_ctx ctx; + + /* Read key and initialize context */ + { + uint8_t key[256]; + size_t keylen = 0; + char *ekey = getenv("KEY"); + FILE *f; + + if (argc == 2) { + if (! (f = fopen(argv[1], "r"))) { + perror(argv[0]); + } + } else { + f = fdopen(3, "r"); + } + + if (f) { + keylen = fread(key, 1, sizeof(key), f); + fclose(f); + } else if (ekey) { + keylen = strlen(ekey); + if (keylen > sizeof(key)) { + keylen = sizeof(key); + } + memcpy(key, ekey, keylen); + } + + if (0 == keylen) { + fprintf(stderr, "Usage: %s [KEYFILE] -#include "rand.h" - -#define ind(mm,x) (*(uint32_t *)((uint8_t *)(mm) + ((x) & ((RANDSIZ-1)<<2)))) -#define rngstep(mix,a,b,mm,m,m2,r,x) \ -{ \ - x = *m; \ - a = (a^(mix)) + *(m2++); \ - *(m++) = y = ind(mm,x) + a + b; \ - *(r++) = b = ind(mm,y>>RANDSIZL) + x; \ -} - -void isaac(struct randctx *ctx) -{ - register uint32_t a, b, x, y, *m, *mm, *m2, *r, *mend; - mm = ctx->randmem; - r = ctx->randrsl; - a = ctx->randa; - b = ctx->randb + (++ctx->randc); - for (m = mm, mend = m2 = m + (RANDSIZ / 2); m < mend;) { - rngstep(a << 13, a, b, mm, m, m2, r, x); - rngstep(a >> 6, a, b, mm, m, m2, r, x); - rngstep(a << 2, a, b, mm, m, m2, r, x); - rngstep(a >> 16, a, b, mm, m, m2, r, x); - } - for (m2 = mm; m2 < mend;) { - rngstep(a << 13, a, b, mm, m, m2, r, x); - rngstep(a >> 6, a, b, mm, m, m2, r, x); - rngstep(a << 2, a, b, mm, m, m2, r, x); - rngstep(a >> 16, a, b, mm, m, m2, r, x); - } - ctx->randb = b; - ctx->randa = a; -} - - -#define mix(a,b,c,d,e,f,g,h) \ -{ \ - a^=b<<11; d+=a; b+=c; \ - b^=c>>2; e+=b; c+=d; \ - c^=d<<8; f+=c; d+=e; \ - d^=e>>16; g+=d; e+=f; \ - e^=f<<10; h+=e; f+=g; \ - f^=g>>4; a+=f; g+=h; \ - g^=h<<8; b+=g; h+=a; \ - h^=a>>9; c+=h; a+=b; \ -} - -/* if (flag==TRUE), then use the contents of randrsl[] to initialize mm[]. */ -void randinit(struct randctx *ctx, uint_fast8_t flag) -{ - uint_fast32_t i; - uint32_t a, b, c, d, e, f, g, h; - uint32_t *m, *r; - ctx->randa = ctx->randb = ctx->randc = 0; - m = ctx->randmem; - r = ctx->randrsl; - a = b = c = d = e = f = g = h = 0x9e3779b9; /* the golden ratio */ - - for (i = 0; i < 4; ++i) { /* scramble it */ - mix(a, b, c, d, e, f, g, h); - } - - if (flag) { - /* initialize using the contents of r[] as the seed */ - for (i = 0; i < RANDSIZ; i += 8) { - a += r[i]; - b += r[i + 1]; - c += r[i + 2]; - d += r[i + 3]; - e += r[i + 4]; - f += r[i + 5]; - g += r[i + 6]; - h += r[i + 7]; - mix(a, b, c, d, e, f, g, h); - m[i] = a; - m[i + 1] = b; - m[i + 2] = c; - m[i + 3] = d; - m[i + 4] = e; - m[i + 5] = f; - m[i + 6] = g; - m[i + 7] = h; - } - /* do a second pass to make all of the seed affect all of m */ - for (i = 0; i < RANDSIZ; i += 8) { - a += m[i]; - b += m[i + 1]; - c += m[i + 2]; - d += m[i + 3]; - e += m[i + 4]; - f += m[i + 5]; - g += m[i + 6]; - h += m[i + 7]; - mix(a, b, c, d, e, f, g, h); - m[i] = a; - m[i + 1] = b; - m[i + 2] = c; - m[i + 3] = d; - m[i + 4] = e; - m[i + 5] = f; - m[i + 6] = g; - m[i + 7] = h; - } - } else { - /* fill in m[] with messy stuff */ - for (i = 0; i < RANDSIZ; i += 8) { - mix(a, b, c, d, e, f, g, h); - m[i] = a; - m[i + 1] = b; - m[i + 2] = c; - m[i + 3] = d; - m[i + 4] = e; - m[i + 5] = f; - m[i + 6] = g; - m[i + 7] = h; - } - } - - isaac(ctx); /* fill in the first set of results */ - ctx->randcnt = RANDSIZ; /* prepare to use the first set of results */ -} - - -#ifdef NEVER - -#include - -int main() -{ - uint32_t i, j; - struct randctx ctx; - ctx.randa = ctx.randb = ctx.randc = (uint32_t) 0; - for (i = 0; i < 256; ++i) - ctx.randrsl[i] = (uint32_t) 0; - randinit(&ctx, 1); - for (i = 0; i < 2; ++i) { - isaac(&ctx); - for (j = 0; j < 256; ++j) { - printf("%.8x", ctx.randrsl[j]); - if ((j & 7) == 7) - printf("\n"); - } - } -} -#endif diff --git a/include/isaac.h b/include/isaac.h deleted file mode 100644 index 14e9adb..0000000 --- a/include/isaac.h +++ /dev/null @@ -1,55 +0,0 @@ -/* ------------------------------------------------------------------------------- -rand.h: definitions for a random number generator -By Bob Jenkins, 1996, Public Domain -MODIFIED: - 960327: Creation (addition of randinit, really) - 970719: use context, not global variables, for internal state - 980324: renamed seed to flag - 980605: recommend RANDSIZL=4 for noncryptography. - 010626: note this is public domain - 101005: update to C99 (neale@lanl.gov) ------------------------------------------------------------------------------- -*/ - -#ifndef __ISAAC_H__ -#define __ISAAC_H__ - -#include - -#define RANDSIZL (8) -#define RANDSIZ (1<randcnt-- ? \ - (isaac(r), (r)->randcnt=RANDSIZ-1, (r)->randrsl[(r)->randcnt]) : \ - (r)->randrsl[(r)->randcnt]) - -#endif /* RAND */ - - -#endif /* __ISAAC_H__ */ diff --git a/include/md5.c b/include/md5.c new file mode 100644 index 0000000..036c900 --- /dev/null +++ b/include/md5.c @@ -0,0 +1,280 @@ +/* + * This code implements the MD5 message-digest algorithm. + * The algorithm is due to Ron Rivest. This code was + * written by Colin Plumb in 1993, no copyright is claimed. + * This code is in the public domain; do with it what you wish. + * + * Equivalent code is available from RSA Data Security, Inc. + * This code has been tested against that, and is equivalent, + * except that you don't need to include two pages of legalese + * with every copy. + * + * To compute the message digest of a chunk of bytes, declare an + * MD5Context structure, pass it to MD5Init, call MD5Update as + * needed on buffers full of bytes, and then call MD5Final, which + * will fill a supplied 16-byte array with the digest. + */ + +/* Brutally hacked by John Walker back from ANSI C to K&R (no + prototypes) to maintain the tradition that Netfone will compile + with Sun's original "cc". */ + +#include /* for memcpy() */ +#include +#include +#include "md5.h" + +void md5_transform(uint32_t buf[4], uint32_t in[16]); + +#ifndef HIGHFIRST +#define byteReverse(buf, len) /* Nothing */ +#else +/* + * Note: this code is harmless on little-endian machines. + */ +static void byteReverse(uint8_t *buf, size_t words) +{ + uint32_t t; + do { + t = (uint32_t) ((unsigned) buf[3] << 8 | buf[2]) << 16 | + ((unsigned) buf[1] << 8 | buf[0]); + *(uint32_t *) buf = t; + buf += 4; + } while (--words); +} +#endif + + +/* + * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious + * initialization constants. + */ +void md5_init(struct md5_context *ctx) +{ + ctx->buf[0] = 0x67452301; + ctx->buf[1] = 0xefcdab89; + ctx->buf[2] = 0x98badcfe; + ctx->buf[3] = 0x10325476; + + ctx->bits[0] = 0; + ctx->bits[1] = 0; +} + +/* + * Update context to reflect the concatenation of another buffer full + * of bytes. + */ +void md5_update(struct md5_context *ctx, + const uint8_t *buf, + size_t len) +{ + uint32_t t; + + /* Update bitcount */ + + t = ctx->bits[0]; + if ((ctx->bits[0] = t + ((uint32_t) len << 3)) < t) + ctx->bits[1]++; /* Carry from low to high */ + ctx->bits[1] += len >> 29; + + t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */ + + /* Handle any leading odd-sized chunks */ + + if (t) { + unsigned char *p = (unsigned char *) ctx->in + t; + + t = 64 - t; + if (len < t) { + memcpy(p, buf, len); + return; + } + memcpy(p, buf, t); + byteReverse(ctx->in, 16); + md5_transform(ctx->buf, (uint32_t *) ctx->in); + buf += t; + len -= t; + } + /* Process data in 64-byte chunks */ + + while (len >= 64) { + memcpy(ctx->in, buf, 64); + byteReverse(ctx->in, 16); + md5_transform(ctx->buf, (uint32_t *) ctx->in); + buf += 64; + len -= 64; + } + + /* Handle any remaining bytes of data. */ + + memcpy(ctx->in, buf, len); +} + +/* + * Final wrapup - pad to 64-byte boundary with the bit pattern + * 1 0* (64-bit count of bits processed, MSB-first) + */ +void md5_final(struct md5_context *ctx, uint8_t *digest) +{ + unsigned int count; + uint8_t *p; + + /* Compute number of bytes mod 64 */ + count = (ctx->bits[0] >> 3) & 0x3F; + + /* Set the first char of padding to 0x80. This is safe since there is + always at least one byte free */ + p = ctx->in + count; + *p++ = 0x80; + + /* Bytes of padding needed to make 64 bytes */ + count = 64 - 1 - count; + + /* Pad out to 56 mod 64 */ + if (count < 8) { + /* Two lots of padding: Pad the first block to 64 bytes */ + memset(p, 0, count); + byteReverse(ctx->in, 16); + md5_transform(ctx->buf, (uint32_t *) ctx->in); + + /* Now fill the next block with 56 bytes */ + memset(ctx->in, 0, 56); + } else { + /* Pad block to 56 bytes */ + memset(p, 0, count - 8); + } + byteReverse(ctx->in, 14); + + /* Append length in bits and transform */ + ((uint32_t *) ctx->in)[14] = ctx->bits[0]; + ((uint32_t *) ctx->in)[15] = ctx->bits[1]; + + md5_transform(ctx->buf, (uint32_t *) ctx->in); + byteReverse((unsigned char *) ctx->buf, 4); + memcpy(digest, ctx->buf, 16); + memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */ +} + + +/* The four core functions - F1 is optimized somewhat */ + +/* #define F1(x, y, z) (x & y | ~x & z) */ +#define F1(x, y, z) (z ^ (x & (y ^ z))) +#define F2(x, y, z) F1(z, x, y) +#define F3(x, y, z) (x ^ y ^ z) +#define F4(x, y, z) (y ^ (x | ~z)) + +/* This is the central step in the MD5 algorithm. */ +#define md5_step(f, w, x, y, z, data, s) \ + ( w += f(x, y, z) + data, w = w<>(32-s), w += x ) + +/* + * The core of the MD5 algorithm, this alters an existing MD5 hash to + * reflect the addition of 16 longwords of new data. MD5Update blocks + * the data and converts bytes into longwords for this routine. + */ +void md5_transform(uint32_t buf[4], uint32_t in[16]) +{ + register uint32_t a, b, c, d; + + a = buf[0]; + b = buf[1]; + c = buf[2]; + d = buf[3]; + + md5_step(F1, a, b, c, d, in[0] + 0xd76aa478, 7); + md5_step(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); + md5_step(F1, c, d, a, b, in[2] + 0x242070db, 17); + md5_step(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); + md5_step(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); + md5_step(F1, d, a, b, c, in[5] + 0x4787c62a, 12); + md5_step(F1, c, d, a, b, in[6] + 0xa8304613, 17); + md5_step(F1, b, c, d, a, in[7] + 0xfd469501, 22); + md5_step(F1, a, b, c, d, in[8] + 0x698098d8, 7); + md5_step(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); + md5_step(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); + md5_step(F1, b, c, d, a, in[11] + 0x895cd7be, 22); + md5_step(F1, a, b, c, d, in[12] + 0x6b901122, 7); + md5_step(F1, d, a, b, c, in[13] + 0xfd987193, 12); + md5_step(F1, c, d, a, b, in[14] + 0xa679438e, 17); + md5_step(F1, b, c, d, a, in[15] + 0x49b40821, 22); + + md5_step(F2, a, b, c, d, in[1] + 0xf61e2562, 5); + md5_step(F2, d, a, b, c, in[6] + 0xc040b340, 9); + md5_step(F2, c, d, a, b, in[11] + 0x265e5a51, 14); + md5_step(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); + md5_step(F2, a, b, c, d, in[5] + 0xd62f105d, 5); + md5_step(F2, d, a, b, c, in[10] + 0x02441453, 9); + md5_step(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); + md5_step(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); + md5_step(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); + md5_step(F2, d, a, b, c, in[14] + 0xc33707d6, 9); + md5_step(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); + md5_step(F2, b, c, d, a, in[8] + 0x455a14ed, 20); + md5_step(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); + md5_step(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); + md5_step(F2, c, d, a, b, in[7] + 0x676f02d9, 14); + md5_step(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); + + md5_step(F3, a, b, c, d, in[5] + 0xfffa3942, 4); + md5_step(F3, d, a, b, c, in[8] + 0x8771f681, 11); + md5_step(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); + md5_step(F3, b, c, d, a, in[14] + 0xfde5380c, 23); + md5_step(F3, a, b, c, d, in[1] + 0xa4beea44, 4); + md5_step(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); + md5_step(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); + md5_step(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); + md5_step(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); + md5_step(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); + md5_step(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); + md5_step(F3, b, c, d, a, in[6] + 0x04881d05, 23); + md5_step(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); + md5_step(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); + md5_step(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); + md5_step(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); + + md5_step(F4, a, b, c, d, in[0] + 0xf4292244, 6); + md5_step(F4, d, a, b, c, in[7] + 0x432aff97, 10); + md5_step(F4, c, d, a, b, in[14] + 0xab9423a7, 15); + md5_step(F4, b, c, d, a, in[5] + 0xfc93a039, 21); + md5_step(F4, a, b, c, d, in[12] + 0x655b59c3, 6); + md5_step(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); + md5_step(F4, c, d, a, b, in[10] + 0xffeff47d, 15); + md5_step(F4, b, c, d, a, in[1] + 0x85845dd1, 21); + md5_step(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); + md5_step(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); + md5_step(F4, c, d, a, b, in[6] + 0xa3014314, 15); + md5_step(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); + md5_step(F4, a, b, c, d, in[4] + 0xf7537e82, 6); + md5_step(F4, d, a, b, c, in[11] + 0xbd3af235, 10); + md5_step(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); + md5_step(F4, b, c, d, a, in[9] + 0xeb86d391, 21); + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; +} + +void +md5_digest(const uint8_t *buf, size_t buflen, uint8_t *digest) +{ + struct md5_context ctx; + + md5_init(&ctx); + md5_update(&ctx, buf, buflen); + md5_final(&ctx, digest); +} + +void +md5_hexdigest(const uint8_t *buf, size_t buflen, char *hexdigest) +{ + uint8_t digest[MD5_DIGEST_LEN]; + int i; + + md5_digest(buf, buflen, digest); + + for (i = 0; i < MD5_DIGEST_LEN; i += 1) { + sprintf(hexdigest + (i*2), "%02x", digest[i]); + } +} diff --git a/include/md5.h b/include/md5.h new file mode 100644 index 0000000..63c7936 --- /dev/null +++ b/include/md5.h @@ -0,0 +1,42 @@ +#ifndef MD5_H +#define MD5_H + +#include + +/* The following tests optimise behaviour on little-endian + machines, where there is no need to reverse the byte order + of 32 bit words in the MD5 computation. By default, + HIGHFIRST is defined, which indicates we're running on a + big-endian (most significant byte first) machine, on which + the byteReverse function in md5.c must be invoked. However, + byteReverse is coded in such a way that it is an identity + function when run on a little-endian machine, so calling it + on such a platform causes no harm apart from wasting time. + If the platform is known to be little-endian, we speed + things up by undefining HIGHFIRST, which defines + byteReverse as a null macro. Doing things in this manner + insures we work on new platforms regardless of their byte + order. */ + +#define HIGHFIRST + +#ifdef __i386__ +#undef HIGHFIRST +#endif + +#define MD5_DIGEST_LEN 16 +#define MD5_HEXDIGEST_LEN (MD5_DIGEST_LEN * 2) + +struct md5_context { + uint32_t buf[4]; + uint32_t bits[2]; + uint8_t in[64]; +}; + +void md5_init(struct md5_context *ctx); +void md5_update(struct md5_context *ctx, const uint8_t *buf, size_t len); +void md5_final(struct md5_context *ctx, uint8_t *digest); +void md5_digest(const uint8_t *buf, size_t buflen, uint8_t *digest); +void md5_hexdigest(const uint8_t *buf, size_t buflen, char *hexdigest); + +#endif /* !MD5_H */ diff --git a/include/rand.c b/include/rand.c new file mode 100644 index 0000000..3f03634 --- /dev/null +++ b/include/rand.c @@ -0,0 +1,65 @@ +#include +#include +#include +#include +#include +#include +#include "arc4.h" + +/* + * + * Random numbers + * + */ + +void +urandom(uint8_t *buf, size_t buflen) +{ + static int initialized = 0; + static struct arc4_ctx ctx; + + if (! initialized) { + int fd = open("/dev/urandom", O_RDONLY); + + if (-1 == fd) { + struct { + time_t time; + pid_t pid; + } bits; + + bits.time = time(NULL); + bits.pid = getpid(); + arc4_init(&ctx, (uint8_t *)&bits, sizeof(bits)); + } else { + uint8_t key[256]; + + read(fd, key, sizeof(key)); + close(fd); + arc4_init(&ctx, key, sizeof(key)); + } + + initialized = 1; + } + + while (buflen--) { + *(buf++) = arc4_out(&ctx); + } +} + +int32_t +rand32() +{ + int32_t ret; + + urandom((uint8_t *)&ret, sizeof(ret)); + return ret; +} + +uint32_t +randu32() +{ + uint32_t ret; + + urandom((uint8_t *)&ret, sizeof(ret)); + return ret; +} diff --git a/include/rand.h b/include/rand.h new file mode 100644 index 0000000..02fc019 --- /dev/null +++ b/include/rand.h @@ -0,0 +1,11 @@ +#ifndef __RAND_H__ +#define __RAND_H__ + +#include +#include + +void urandom(void *buf, size_t buflen); +int32_t rand32(); +uint32_t randu32(); + +#endif /* __RAND_H__ */ diff --git a/include/test.c b/include/test.c new file mode 100644 index 0000000..0301a26 --- /dev/null +++ b/include/test.c @@ -0,0 +1,46 @@ +#include +#include +#include "rand.h" +#include "md5.h" +#include "token.h" + +int +main() +{ + int i; + uint8_t zeroes[64] = {0}; + uint8_t digest[MD5_DIGEST_LEN]; + + for (i = 0; i < 10; i += 1) { + printf("%d ", randu32() % 10); + } + + printf("\n4ae71336e44bf9bf79d2752e234818a5\n"); + + md5_digest(zeroes, 16, digest); + for (i = 0; i < sizeof(digest); i += 1) { + printf("%02x", digest[i]); + } + printf("\n"); + + { + char hd[MD5_HEXDIGEST_LEN + 1] = {0}; + + md5_hexdigest(zeroes, 16, hd); + printf("%s\n", hd); + } + + { + ssize_t len; + char token[TOKEN_MAX]; + + len = read_token("foo", 0, 4, token, sizeof(token)); + if (-1 != len) { + printf("rut roh\n"); + } else { + printf("Good.\n"); + } + } + + return 0; +} diff --git a/include/token.c b/include/token.c index 4edd897..9fbe6d3 100644 --- a/include/token.c +++ b/include/token.c @@ -12,13 +12,18 @@ #define CTF_BASE "/var/lib/ctf" #endif +/* + * + * ARC-4 stuff + * + */ + struct arc4_ctx { uint8_t S[256]; uint8_t i; uint8_t j; }; - #define swap(a, b) do {int _swap=a; a=b, b=_swap;} while (0) void @@ -39,29 +44,28 @@ arc4_init(struct arc4_ctx *ctx, uint8_t const *key, size_t keylen) ctx->j = 0; } -void -arc4_crypt(struct arc4_ctx *ctx, - uint8_t *obuf, uint8_t const *ibuf, size_t buflen) +uint8_t +arc4_out(struct arc4_ctx *ctx) { - int i = ctx->i; - int j = ctx->j; - size_t k; - - for (k = 0; k < buflen; k += 1) { - uint8_t mask; - - i = (i + 1) % 256; - j = (j + ctx->S[i]) % 256; - swap(ctx->S[i], ctx->S[j]); - mask = ctx->S[(ctx->S[i] + ctx->S[j]) % 256]; - obuf[k] = ibuf[k] ^ mask; - } - ctx->i = i; - ctx->j = j; + ctx->i = (ctx->i + 1) % 256; + ctx->j = (ctx->j + ctx->S[ctx->i]) % 256; + swap(ctx->S[ctx->i], ctx->S[ctx->j]); + return ctx->S[(ctx->S[ctx->i] + ctx->S[ctx->j]) % 256]; } void -arc4_crypt_buffer(uint8_t const *key, size_t keylen, +arc4_crypt(struct arc4_ctx *ctx, + uint8_t *obuf, const uint8_t *ibuf, size_t buflen) +{ + size_t k; + + for (k = 0; k < buflen; k += 1) { + obuf[k] = ibuf[k] ^ arc4_out(ctx); + } +} + +void +arc4_crypt_buffer(const uint8_t *key, size_t keylen, uint8_t *buf, size_t buflen) { struct arc4_ctx ctx; @@ -70,6 +74,11 @@ arc4_crypt_buffer(uint8_t const *key, size_t keylen, arc4_crypt(&ctx, buf, buf, buflen); } +/* + * + */ + + ssize_t read_token_fd(int fd, diff --git a/include/token.h b/include/token.h index ac4f95b..4034254 100644 --- a/include/token.h +++ b/include/token.h @@ -8,13 +8,6 @@ #define TOKEN_MAX 80 /* ARC4 functions, in case anybody wants 'em */ -struct arc4_ctx; -void arc4_init(struct arc4_ctx *ctx, - uint8_t const *key, size_t keylen); -void arc4_crypt(struct arc4_ctx *ctx, - uint8_t *obuf, uint8_t const *ibuf, size_t buflen); -void arc4_crypt_buffer(uint8_t const *key, size_t keylen, - uint8_t *buf, size_t buflen); ssize_t read_token_fd(int fd, uint8_t const *key, size_t keylen, diff --git a/packages/ctfbase/ctfbase.mk b/packages/ctfbase/ctfbase.mk new file mode 100644 index 0000000..8b89e09 --- /dev/null +++ b/packages/ctfbase/ctfbase.mk @@ -0,0 +1,18 @@ +CTFBASE_PKGDIR = $(TARGET)/ctfbase + +ctfbase-install: ctfbase-build + mkdir -p $(CTFBASE_PKGDIR)/bin/ + + $(call COPYTREE, packages/ctfbase/service, $(CTFBASE_PKGDIR)/service) + + cp packages/ctfbase/src/tokencli $(CTFBASE_PKGDIR)/bin/ + cp packages/ctfbase/src/arc4 $(CTFBASE_PKGDIR)/bin/ + +ctfbase-clean: + rm -rf $(CTFBASE_PKGDIR) + $(MAKE) -C packages/ctfbase/src clean + +ctfbase-build: + $(MAKE) -C packages/ctfbase/src build + +PACKAGES += ctfbase diff --git a/packages/tokens/service/tokens/tokens b/packages/ctfbase/service/ctfd/ctfd similarity index 56% rename from packages/tokens/service/tokens/tokens rename to packages/ctfbase/service/ctfd/ctfd index 0826283..11e724e 100755 --- a/packages/tokens/service/tokens/tokens +++ b/packages/ctfbase/service/ctfd/ctfd @@ -1,6 +1,7 @@ #! /bin/sh while true; do + # Get new tokens for dn in /opt/*/tokens/*; do [ -d $dn ] || continue puzzle=$(basename $dn) @@ -9,5 +10,16 @@ while true; do -e /opt/tokens/bin/tokencli $category $dn/category.key 3>&1 | \ /opt/tokens/bin/arc4 $dn/enc.key > /var/lib/ctf/tokens/$puzzle done + + # Fetch list of teams + wget -q -P /var/lib/ctf http://10.0.0.2/teams.txt & + + # Archive state + state=/var/www/state.tar.gz.rc4 + tar cf - /var/lib/ctf | \ + gzip -c | \ + KEY='crashmaster' arc4 > $state.tmp + mv $state.tmp $state + sleep 60 done diff --git a/packages/tokens/service/tokens/log/run b/packages/ctfbase/service/ctfd/log/run similarity index 100% rename from packages/tokens/service/tokens/log/run rename to packages/ctfbase/service/ctfd/log/run diff --git a/packages/ctfbase/service/ctfd/run b/packages/ctfbase/service/ctfd/run new file mode 100755 index 0000000..431f9f9 --- /dev/null +++ b/packages/ctfbase/service/ctfd/run @@ -0,0 +1,12 @@ +#! /bin/sh -e + +exec 2>&1 + +# Set up networking for all CTF ip +ip link set eth0 up +if ! ip route | grep -q default; then + ip route add default via 10.0.0.1 || exit 1 +fi + +install -o root -m 0755 -d /var/lib/ctf/tokens +exec ./ctfd diff --git a/packages/tokens/src/Makefile b/packages/ctfbase/src/Makefile similarity index 57% rename from packages/tokens/src/Makefile rename to packages/ctfbase/src/Makefile index 1bd9d34..5b21ecc 100644 --- a/packages/tokens/src/Makefile +++ b/packages/ctfbase/src/Makefile @@ -1,6 +1,7 @@ build: tokencli arc4 -arc4: arc4.o arc4-main.o +arc4: arc4.c + $(CC) $(CFLAGS) $(LDFLAGS) -DARC4_MAIN -o $@ $< tokencli: tokencli.o arc4.o diff --git a/packages/tokens/src/arc4.c b/packages/ctfbase/src/arc4.c similarity index 100% rename from packages/tokens/src/arc4.c rename to packages/ctfbase/src/arc4.c diff --git a/packages/tokens/src/arc4.h b/packages/ctfbase/src/arc4.h similarity index 100% rename from packages/tokens/src/arc4.h rename to packages/ctfbase/src/arc4.h diff --git a/packages/tokens/src/tokencli.c b/packages/ctfbase/src/tokencli.c similarity index 100% rename from packages/tokens/src/tokencli.c rename to packages/ctfbase/src/tokencli.c diff --git a/packages/logger/service/logger/finish b/packages/logger/service/logger/finish new file mode 100755 index 0000000..6317f74 --- /dev/null +++ b/packages/logger/service/logger/finish @@ -0,0 +1,4 @@ +#! /bin/sh + +IP=$(cat ip.txt) +ip addr del $IP dev eth0 diff --git a/packages/logger/service/logger/ip.txt b/packages/logger/service/logger/ip.txt new file mode 100644 index 0000000..b7c75a4 --- /dev/null +++ b/packages/logger/service/logger/ip.txt @@ -0,0 +1 @@ +10.0.0.14/24 diff --git a/packages/logger/service/logger/run b/packages/logger/service/logger/run index aa0462d..f0bf6ab 100755 --- a/packages/logger/service/logger/run +++ b/packages/logger/service/logger/run @@ -1,4 +1,6 @@ -#! /bin/sh +#! /bin/sh -e exec 2>&1 -exec tcpsvd 0 4104 /opt/logger/bin/logger +IP=$(cat ip.txt) +ip addr add $IP label eth0:logger dev eth0 +exec tcpsvd ${IP#/*} 1958 /opt/logger/bin/logger diff --git a/packages/logger/src/Makefile b/packages/logger/src/Makefile index d7cc0df..980cb6d 100644 --- a/packages/logger/src/Makefile +++ b/packages/logger/src/Makefile @@ -11,4 +11,4 @@ install: $(TARGETS) install -m 0755 $(TARGETS) $(DESTDIR)/bin clean: - rm -f *.o $(TARGETS) \ No newline at end of file + rm -f *.o $(TARGETS) diff --git a/packages/logger/src/logger.c b/packages/logger/src/logger.c index 11ae1bb..e8159af 100644 --- a/packages/logger/src/logger.c +++ b/packages/logger/src/logger.c @@ -1,10 +1,34 @@ -#include +/** logger.c - generate fake log messages (part of dirtbags CTF) + * + * Author: Neale Pickett + * + * This software has been authored by an employee or employees of Los + * Alamos National Security, LLC, operator of the Los Alamos National + * Laboratory (LANL) under Contract No. DE-AC52-06NA25396 with the + * U.S. Department of Energy. The U.S. Government has rights to use, + * reproduce, and distribute this software. The public may copy, + * distribute, prepare derivative works and publicly display this + * software without charge, provided that this Notice and any statement + * of authorship are reproduced on all copies. Neither the Government + * nor LANS makes any warranty, express or implied, or assumes any + * liability or responsibility for the use of this software. If + * software is modified to produce derivative works, such modified + * software should be clearly marked, so as not to confuse it with the + * version available from LANL. + */ + + #include #include #include #include #include -#include "token.h" + +#ifdef STANDALONE +# define TOKEN_MAX 50 +#else +# include "token.h" +#endif #define PID_MAX 32768 #define QSIZE 200 @@ -27,12 +51,16 @@ read_tokens() char name[40]; for (i = 0; i < sizeof(token)/sizeof(*token); i += 1) { +#ifdef STANDALONE + strcpy(token[i], "logger:xylep-donut-nanox"); +#else /* This can't grow beyond 40. Think about it. */ sprintf(name, "logger%d", i); len = read_token(name, key, sizeof(key), token[i], sizeof(token[i])); if ((-1 == len) || (len >= sizeof(token[i]))) abort(); token[i][len] = '\0'; +#endif } } diff --git a/packages/mcp/mcp.mk b/packages/mcp/mcp.mk index 6d068f7..e91d9d8 100644 --- a/packages/mcp/mcp.mk +++ b/packages/mcp/mcp.mk @@ -6,9 +6,7 @@ mcp-install: mcp-build $(call COPYTREE, packages/mcp/bin, $(MCP_PKGDIR)/bin) cp packages/mcp/src/in.tokend $(MCP_PKGDIR)/bin/ cp packages/mcp/src/pointscli $(MCP_PKGDIR)/bin/ - cp packages/mcp/src/tokencli $(MCP_PKGDIR)/bin/ cp packages/mcp/src/puzzles.cgi $(MCP_PKGDIR)/bin/ - cp packages/mcp/src/arc4 $(MCP_PKGDIR)/bin/ $(call COPYTREE, packages/mcp/service, $(MCP_PKGDIR)/service) diff --git a/packages/mcp/service/eth0/run b/packages/mcp/service/eth0/run deleted file mode 100755 index 58a2f37..0000000 --- a/packages/mcp/service/eth0/run +++ /dev/null @@ -1,8 +0,0 @@ -#! /bin/sh -e - -hostname mcp - -ifconfig eth0 10.0.0.2 netmask 255.255.0.0 -route add default gw 10.0.0.1 - -exec inotifyd true $(pwd):x diff --git a/packages/mcp/service/httpd/mathopd.conf b/packages/mcp/service/httpd/mathopd.conf index a1e645e..00dcb97 100644 --- a/packages/mcp/service/httpd/mathopd.conf +++ b/packages/mcp/service/httpd/mathopd.conf @@ -41,6 +41,8 @@ Control { } Server { + Address 10.0.0.2 + Virtual { AnyHost Control { diff --git a/packages/mcp/service/tokend/run b/packages/mcp/service/tokend/run index 211a9b9..692d02f 100755 --- a/packages/mcp/service/tokend/run +++ b/packages/mcp/service/tokend/run @@ -2,6 +2,8 @@ exec 2>&1 +ip addr add 10.0.0.2/24 label eth0:mcp dev eth0 + DB=/var/lib/ctf/tokens.db if [ ! -f $DB ]; then diff --git a/packages/mcp/src/Makefile b/packages/mcp/src/Makefile index 35fa5c5..02845a2 100644 --- a/packages/mcp/src/Makefile +++ b/packages/mcp/src/Makefile @@ -1,13 +1,13 @@ CFLAGS = -Wall -Werror -TARGETS = in.tokend tokencli claim.cgi +TARGETS = in.tokend claim.cgi TARGETS += puzzler.cgi puzzles.cgi -TARGETS += pointscli mktoken arc4 +TARGETS += pointscli mktoken all: build build: $(TARGETS) -in.tokend: in.tokend.o arc4.o common.o +in.tokend: in.tokend.o arc4.o md5.o common.o tokencli: tokencli.o arc4.o pointscli: pointscli.o common.o mktoken: mktoken.o common.o diff --git a/packages/mcp/src/arc4-main.c b/packages/mcp/src/arc4-main.c deleted file mode 120000 index d91405e..0000000 --- a/packages/mcp/src/arc4-main.c +++ /dev/null @@ -1 +0,0 @@ -../../tokens/src/arc4-main.c \ No newline at end of file diff --git a/packages/mcp/src/md5.c b/packages/mcp/src/md5.c new file mode 120000 index 0000000..b1ccd62 --- /dev/null +++ b/packages/mcp/src/md5.c @@ -0,0 +1 @@ +../../../include/md5.c \ No newline at end of file diff --git a/packages/mcp/src/md5.h b/packages/mcp/src/md5.h new file mode 120000 index 0000000..b229155 --- /dev/null +++ b/packages/mcp/src/md5.h @@ -0,0 +1 @@ +../../../include/md5.h \ No newline at end of file diff --git a/packages/mcp/src/tokencli.c b/packages/mcp/src/tokencli.c deleted file mode 120000 index 4ae82d2..0000000 --- a/packages/mcp/src/tokencli.c +++ /dev/null @@ -1 +0,0 @@ -../../tokens/src/tokencli.c \ No newline at end of file diff --git a/packages/octopus/service/octopus-redirect/octopus-redirect b/packages/octopus/service/octopus-redirect/octopus-redirect new file mode 100755 index 0000000..c6f06c6 --- /dev/null +++ b/packages/octopus/service/octopus-redirect/octopus-redirect @@ -0,0 +1,3 @@ +#! /bin/sh + +echo 'Try UDP.' diff --git a/packages/octopus/service/octopus-redirect/run b/packages/octopus/service/octopus-redirect/run new file mode 100755 index 0000000..f404009 --- /dev/null +++ b/packages/octopus/service/octopus-redirect/run @@ -0,0 +1,5 @@ +#! /bin/sh -e + +IP=$(cat ../octopus/ip.txt) +sv s octopus >/dev/null || exit 1 +exec tcpsvd ${IP#/*} 8888 ./octopus-redirect diff --git a/packages/octopus/service/octopus/finish b/packages/octopus/service/octopus/finish new file mode 100755 index 0000000..6317f74 --- /dev/null +++ b/packages/octopus/service/octopus/finish @@ -0,0 +1,4 @@ +#! /bin/sh + +IP=$(cat ip.txt) +ip addr del $IP dev eth0 diff --git a/packages/octopus/service/octopus/ip.txt b/packages/octopus/service/octopus/ip.txt new file mode 100644 index 0000000..1628247 --- /dev/null +++ b/packages/octopus/service/octopus/ip.txt @@ -0,0 +1 @@ +10.0.0.8/24 diff --git a/packages/octopus/service/octopus/run b/packages/octopus/service/octopus/run index 6bdd947..2b7df70 100755 --- a/packages/octopus/service/octopus/run +++ b/packages/octopus/service/octopus/run @@ -1,4 +1,6 @@ -#! /bin/sh +#! /bin/sh -e exec 2>&1 -exec /opt/octopus/bin/octopus +IP=$(cat ip.txt) +ip addr add $IP label eth0:octopus dev eth0 +exec /opt/octopus/bin/octopus ${IP%/*} diff --git a/packages/octopus/src/octopus.c b/packages/octopus/src/octopus.c index 1b9dd25..2020d1d 100644 --- a/packages/octopus/src/octopus.c +++ b/packages/octopus/src/octopus.c @@ -194,17 +194,17 @@ struct bound_port { } bound_ports[PORTS]; int -bind_port(int fd, uint16_t port) { - struct sockaddr_in addr; +bind_port(struct in_addr *addr, int fd, uint16_t port) { + struct sockaddr_in saddr; - addr.sin_family = AF_INET; - addr.sin_port = htons(port); - addr.sin_addr.s_addr = INADDR_ANY; - return bind(fd, (struct sockaddr *)&addr, sizeof(addr)); + saddr.sin_family = AF_INET; + saddr.sin_port = htons(port); + memcpy(&saddr.sin_addr.s_addr, addr, sizeof(struct in_addr)); + return bind(fd, (struct sockaddr *)&saddr, sizeof(saddr)); } int -rebind() +rebind(struct in_addr *addr) { static int offset = 0; char token[200]; @@ -235,7 +235,7 @@ rebind() bound_ports[i + offset].fd = socket(PF_INET, SOCK_DGRAM, 0); do { port = (random() % 56635) + 10000; - ret = bind_port(bound_ports[i + offset].fd, port); + ret = bind_port(addr, bound_ports[i + offset].fd, port); } while (-1 == ret); /* Set the last guy's port number */ @@ -337,15 +337,25 @@ loop() int main(int argc, char *argv[]) { - int ret; - int i; - time_t last = time(NULL); + int ret; + int i; + time_t last = time(NULL); + struct in_addr addr; /* The random seed isn't super important here. */ - srand(8); + srand(last); + + if (argc > 1) { + if (-1 == inet_aton(argv[1], &addr)) { + fprintf(stderr, "invalid address: %s\n", argv[1]); + return EX_IOERR; + } + } else { + addr.s_addr = INADDR_ANY; + } bound_ports[0].fd = socket(PF_INET, SOCK_DGRAM, 0); - ret = bind_port(bound_ports[0].fd, 8888); + ret = bind_port(&addr, bound_ports[0].fd, 8888); if (-1 == ret) { perror("bind port 8888"); return EX_IOERR; @@ -354,7 +364,7 @@ main(int argc, char *argv[]) for (i = 1; i < PORTS; i += 1) { bound_ports[i].fd = -1; } - if (-1 == rebind()) { + if (-1 == rebind(&addr)) { perror("initial binding"); return EX_IOERR; } @@ -364,7 +374,7 @@ main(int argc, char *argv[]) if (last + 4 < now) { last = now; - if (-1 == rebind()) break; + if (-1 == rebind(&addr)) break; } } diff --git a/packages/printf/service/printf/finish b/packages/printf/service/printf/finish new file mode 100755 index 0000000..6317f74 --- /dev/null +++ b/packages/printf/service/printf/finish @@ -0,0 +1,4 @@ +#! /bin/sh + +IP=$(cat ip.txt) +ip addr del $IP dev eth0 diff --git a/packages/printf/service/printf/ip.txt b/packages/printf/service/printf/ip.txt new file mode 100644 index 0000000..fb7ede6 --- /dev/null +++ b/packages/printf/service/printf/ip.txt @@ -0,0 +1 @@ +10.0.0.91 diff --git a/packages/printf/service/printf/run b/packages/printf/service/printf/run index 512dcab..57de4a7 100755 --- a/packages/printf/service/printf/run +++ b/packages/printf/service/printf/run @@ -1,11 +1,14 @@ -#! /bin/sh +#! /bin/sh -e exec 2>&1 +IP=$(cat ip.txt) +ip addr add $IP label eth0:printf dev eth0 + # So I say to him, "Alex, what's a good high port number for a CTF category?" # And he says, "6" # And I say, "no, it has to be bigger than 1000" # And he says, "how about 9001, because that's bigger than 9000" -# So, okay. +# Okay. -exec tcpsvd 0 9001 ./run-printf +exec tcpsvd ${IP#/*} 9001 ./run-printf diff --git a/packages/pwnables/service/eth0.pwn/run b/packages/pwnables/service/eth0.pwn/run deleted file mode 100755 index 64d7d36..0000000 --- a/packages/pwnables/service/eth0.pwn/run +++ /dev/null @@ -1,11 +0,0 @@ -#! /bin/sh - -if [ -d /opt/mcp ]; then - sv d . - exit -fi - -hostname pwnables -ifconfig eth0 10.0.0.10 netmask 255.255.0.0 -route add default gw 10.0.0.1 -exec inotifyd true $(pwd):x diff --git a/packages/pwnables/service/pwnables/finish b/packages/pwnables/service/pwnables/finish new file mode 100755 index 0000000..6317f74 --- /dev/null +++ b/packages/pwnables/service/pwnables/finish @@ -0,0 +1,4 @@ +#! /bin/sh + +IP=$(cat ip.txt) +ip addr del $IP dev eth0 diff --git a/packages/pwnables/service/pwnables/ip.txt b/packages/pwnables/service/pwnables/ip.txt new file mode 100644 index 0000000..2e7cb07 --- /dev/null +++ b/packages/pwnables/service/pwnables/ip.txt @@ -0,0 +1 @@ +10.0.0.3/24 diff --git a/packages/pwnables/service/pwnables/run b/packages/pwnables/service/pwnables/run index 4d8487b..42cdbe5 100755 --- a/packages/pwnables/service/pwnables/run +++ b/packages/pwnables/service/pwnables/run @@ -1,5 +1,9 @@ #! /bin/sh -e +# Configure IP address +IP=$(cat ip.txt) +ip addr add $IP label eth0:pwnables dev eth0 + # Set up chroot environment # We never umount any of this since it's all just in RAM mkdir -p /mnt/pwnables-root diff --git a/packages/pwnables/service/sshd.pwn/log/run b/packages/pwnables/service/sshd.pwn/log/run deleted file mode 100755 index 4794c8e..0000000 --- a/packages/pwnables/service/sshd.pwn/log/run +++ /dev/null @@ -1,3 +0,0 @@ -#! /bin/sh - -exec logger -t sshd diff --git a/packages/pwnables/service/sshd.pwn/rsa.key b/packages/pwnables/service/sshd.pwn/rsa.key deleted file mode 100644 index f530471..0000000 Binary files a/packages/pwnables/service/sshd.pwn/rsa.key and /dev/null differ diff --git a/packages/pwnables/service/sshd.pwn/run b/packages/pwnables/service/sshd.pwn/run deleted file mode 100755 index 1100af4..0000000 --- a/packages/pwnables/service/sshd.pwn/run +++ /dev/null @@ -1,10 +0,0 @@ -#! /bin/sh - -exec 2>&1 - -if [ -d /opt/mcp ]; then - sv d . - exit -fi - -exec dropbear -r ./rsa.key -E -F diff --git a/packages/rlyeh/rlyeh.mk b/packages/rlyeh/rlyeh.mk new file mode 100644 index 0000000..60a921f --- /dev/null +++ b/packages/rlyeh/rlyeh.mk @@ -0,0 +1,27 @@ +RLYEH_PKGDIR = $(TARGET)/rlyeh +RLYEH_BUILDDIR = $(BUILD)/rlyeh +RLYEH_TAR = $(CACHE)/rlyeh.tar.gz +RLYEH_URL = "http://woozle.org/~neale/gitweb.cgi?p=rlyeh;a=snapshot;h=master;sf=tgz" + +$(RLYEH_TAR): + @ mkdir -p $(@D) + wget -O $@ $(RLYEH_URL) + +rlyeh-source: $(RLYEH_BUILDDIR)/rlyeh +$(RLYEH_BUILDDIR)/rlyeh: $(RLYEH_TAR) + mkdir -p $(RLYEH_BUILDDIR) + zcat $(RLYEH_TAR) | (cd $(RLYEH_BUILDDIR) && tar xf -) + +rlyeh-build: rlyeh-source + $(MAKE) -C $(RLYEH_BUILDDIR)/rlyeh + +rlyeh-install: rlyeh-build + mkdir -p $(RLYEH_PKGDIR)/bin + cp $(RLYEH_BUILDDIR)/rlyeh/rlyeh $(RLYEH_PKGDIR)/bin + + $(call COPYTREE, packages/rlyeh/service, $(RLYEH_PKGDIR)/service) + +rlyeh-clean: + rm -rf $(RLYEH_BUILDDIR) + +PACKAGES += rlyeh diff --git a/packages/rlyeh/service/rlyeh/finish b/packages/rlyeh/service/rlyeh/finish new file mode 100755 index 0000000..54ba047 --- /dev/null +++ b/packages/rlyeh/service/rlyeh/finish @@ -0,0 +1,4 @@ +#! /bin/sh + +read IP < ip.txt +ip addr del $IP dev eth0 diff --git a/packages/rlyeh/service/rlyeh/ip.txt b/packages/rlyeh/service/rlyeh/ip.txt new file mode 100644 index 0000000..6ac003d --- /dev/null +++ b/packages/rlyeh/service/rlyeh/ip.txt @@ -0,0 +1 @@ +10.0.0.28/24 diff --git a/packages/rlyeh/service/rlyeh/rlyeh-ctf b/packages/rlyeh/service/rlyeh/rlyeh-ctf new file mode 100755 index 0000000..1ea6aca --- /dev/null +++ b/packages/rlyeh/service/rlyeh/rlyeh-ctf @@ -0,0 +1,42 @@ +#! /bin/sh + +base=${CTF_BASE:-/var/lib/ctf} + +read -p "Team password: " -r teamhash + +if ! KEY='Too much cheese.' arc4 < $base/teams.txt | grep -q -F -e "$teamhash"; then + echo 'No such team.' + exit +fi + +cd $base/rlyeh + +if [ -f $teamhash ]; then + now=$(date +%s) + ts=$(stat -c %Y $teamhash) + d=$(expr $now - $ts) + if [ $d -lt 60 ]; then + echo 'You are trying to connect too fast.' + exit + fi +else + echo 0 > $teamhash +fi +read level < $teamhash + +( + if ! flock -n 8; then + echo 'Your team is already logged in.' + exit + fi + + echo "Your team is on level $level." + echo + + if ./rlyeh $level; then + echo "10 points for Gryffindor!" + expr $level + 1 > $teamhash + else + touch $teamhash + fi +) 8<$teamhash diff --git a/packages/rlyeh/service/rlyeh/run b/packages/rlyeh/service/rlyeh/run new file mode 100755 index 0000000..40644a0 --- /dev/null +++ b/packages/rlyeh/service/rlyeh/run @@ -0,0 +1,10 @@ +#! /bin/sh -e + +exec 2>&1 +read IP < ip.txt +ip addr add $IP label eth0:rlyeh dev eth0 + +dir=/var/lib/ctf/rlyeh +install -o nobody -d $dir + +exec setuidgid nobody tcpsvd ${IP#/*} 1928 ./rlyeh-ctf diff --git a/packages/mcp/service/sshd/finish b/packages/sshd/service/sshd/finish similarity index 100% rename from packages/mcp/service/sshd/finish rename to packages/sshd/service/sshd/finish diff --git a/packages/mcp/service/sshd/log/run b/packages/sshd/service/sshd/log/run similarity index 100% rename from packages/mcp/service/sshd/log/run rename to packages/sshd/service/sshd/log/run diff --git a/packages/mcp/service/sshd/rsa.key b/packages/sshd/service/sshd/rsa.key similarity index 100% rename from packages/mcp/service/sshd/rsa.key rename to packages/sshd/service/sshd/rsa.key diff --git a/packages/mcp/service/sshd/run b/packages/sshd/service/sshd/run similarity index 100% rename from packages/mcp/service/sshd/run rename to packages/sshd/service/sshd/run diff --git a/packages/tokens/service/tokens/run b/packages/tokens/service/tokens/run deleted file mode 100755 index 25df271..0000000 --- a/packages/tokens/service/tokens/run +++ /dev/null @@ -1,5 +0,0 @@ -#! /bin/sh - -exec 2>&1 -install -o root -m 0755 -d /var/lib/ctf/tokens -exec ./tokens diff --git a/packages/tokens/setup b/packages/tokens/setup deleted file mode 100755 index e864e0d..0000000 --- a/packages/tokens/setup +++ /dev/null @@ -1,4 +0,0 @@ -#! /bin/sh - -cp -r service/* /var/service -mkdir -p /var/lib/ctf/tokens diff --git a/packages/tokens/src/arc4-main.c b/packages/tokens/src/arc4-main.c deleted file mode 100644 index 9332685..0000000 --- a/packages/tokens/src/arc4-main.c +++ /dev/null @@ -1,58 +0,0 @@ -#include -#include -#include -#include -#include -#include "arc4.h" - -int -main(int argc, char *argv[]) -{ - struct arc4_ctx ctx; - - /* Read key and initialize context */ - { - uint8_t key[256]; - size_t keylen = 0; - char *ekey = getenv("KEY"); - FILE *f; - - if (argc == 2) { - if (! (f = fopen(argv[1], "r"))) { - perror(argv[0]); - } - } else { - f = fdopen(3, "r"); - } - - if (f) { - keylen = fread(key, 1, sizeof(key), f); - fclose(f); - } else if (ekey) { - keylen = strlen(ekey); - if (keylen > sizeof(key)) { - keylen = sizeof(key); - } - memcpy(key, ekey, keylen); - } - - if (0 == keylen) { - fprintf(stderr, "Usage: %s [KEYFILE]