Merge branch 'master' of fozzie.woozle.org:projects/ctf

This commit is contained in:
Neale Pickett 2012-01-31 16:51:44 -07:00
commit fe6b1e3b52
16 changed files with 7234 additions and 33 deletions

View File

@ -26,6 +26,10 @@ Course questions should be directed to the appropriate instructor:
General questions about Tracer FIRE may be sent to General questions about Tracer FIRE may be sent to
Neale Pickett <neale@lanl.gov> Neale Pickett <neale@lanl.gov>
Remember: the exercise network should be considered
hostile! Do not bring anything sensitive on your laptop,
and make sure you back everything up.
Looking forward to seeing you in Santa Fe next week, Looking forward to seeing you in Santa Fe next week,
-- --

5468
doc/2012-02-TF4/layout.dxf Normal file

File diff suppressed because it is too large Load Diff

1559
doc/2012-02-TF4/style.svg Normal file

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 110 KiB

View File

@ -0,0 +1,19 @@
COWBULL_PKGDIR = $(TARGET)/cowbull
cowbull-install: cowbull-build
mkdir -p $(COWBULL_PKGDIR)
mkdir -p $(COWBULL_PKGDIR)/bin/
$(MAKE) -C packages/cowbull/src install DESTDIR=$(CURDIR)/$(COWBULL_PKGDIR)
$(call COPYTREE, packages/cowbull/service, $(COWBULL_PKGDIR)/service)
cp packages/cowbull/tokens.txt $(COWBULL_PKGDIR)/
cowbull-clean:
rm -rf $(COWBULL_PKGDIR)
$(MAKE) -C packages/cowbull/src clean
cowbull-build:
$(MAKE) -C packages/cowbull/src build
PACKAGES += cowbull

View File

@ -0,0 +1,4 @@
#! /bin/sh
read IP < ip.txt
ip addr del $IP dev eth0

View File

@ -0,0 +1 @@
fd84:b410:3441::ec6/64

View File

@ -0,0 +1,3 @@
#! /bin/sh
exec svlogd -tt $PWD

View File

@ -0,0 +1,7 @@
#! /bin/sh -e
exec 2>&1
read IP < ip.txt
ip addr add $IP dev eth0 || true
exec setuidgid nobody /opt/cowbull/bin/cowd < /opt/cowbull/tokens.txt

View File

@ -1 +1,11 @@
DESTDIR ?= /tmp
all: cowd cowcli all: cowd cowcli
cowcli: CC=cc
install: all
cp cowd cowcli $(DESTDIR)/bin/
clean:
rm -f cowd cowcli

View File

@ -9,10 +9,17 @@
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/wait.h> #include <sys/wait.h>
#include <netdb.h>
#include <fcntl.h> #include <fcntl.h>
#define DEBUG #define NODEBUG
#ifdef DEBUG
# define PORT 4444
#else
# define PORT 44
#endif
int int
bind_port(int fd, const struct in6_addr *addr, uint16_t port) bind_port(int fd, const struct in6_addr *addr, uint16_t port)
@ -86,7 +93,7 @@ main(int argc, char *argv[])
long answer = 0; long answer = 0;
int sock; int sock;
int i; int i;
struct in6_addr addr; struct addrinfo *addr;
uint32_t token = 0; uint32_t token = 0;
FILE *in, *out; FILE *in, *out;
@ -94,20 +101,31 @@ main(int argc, char *argv[])
signal(SIGCHLD, sigchld); signal(SIGCHLD, sigchld);
if (0 >= inet_pton(AF_INET6, argv[1], &addr)) { if (argc < 2) {
fprintf(stderr, "invalid address: %s\n", argv[1]); fprintf(stderr, "Usage: %s SERVER\n", argv[0]);
return EX_USAGE;
}
{
struct addrinfo hints = { 0 };
hints.ai_family = PF_INET6;
hints.ai_socktype = SOCK_DGRAM;
hints.ai_flags = AI_NUMERICHOST;
if (0 != getaddrinfo(argv[1], "3782", &hints, &addr)) {
perror("Resolving address");
return EX_IOERR; return EX_IOERR;
} }
}
/* /*
* Set up socket * Set up socket
*/ */
sock = socket(AF_INET6, SOCK_DGRAM, 0); sock = socket(AF_INET6, SOCK_DGRAM, 0);
if (-1 == bind_port(sock, &in6addr_any, 44)) { if (-1 == bind_port(sock, &in6addr_any, PORT)) {
perror("Binding UDP port 44"); perror("Binding UDP port 44");
#ifndef DEBUG
return EX_IOERR; return EX_IOERR;
#endif
} }
if (argv[2]) { if (argv[2]) {
@ -139,7 +157,7 @@ main(int argc, char *argv[])
} }
/* Send the guess */ /* Send the guess */
if (-1 == sendto(sock, &g, sizeof g, 0, &addr, sizeof addr)) { if (-1 == sendto(sock, &g, sizeof g, 0, addr->ai_addr, addr->ai_addrlen)) {
perror("Sending packet"); perror("Sending packet");
return EX_IOERR; return EX_IOERR;
} }
@ -156,15 +174,20 @@ main(int argc, char *argv[])
return EX_IOERR; return EX_IOERR;
case 1: case 1:
/* It's a score */ /* It's a score */
printf("%02x\n", buf[0]);
break;
case 4: case 4:
/* New game token */ /* New game token */
printf("NEW GAME\n");
token = *((uint32_t *) buf);
break;
default: default:
/* You win: this is your CTF token */ /* You win: this is your CTF token */
buf[len] = 0;
printf("A WINNER IS YOU: %s\n", buf);
break;
} }
} }
/* parse result */
/* display result */
} }
return 0; return 0;

View File

@ -14,6 +14,8 @@
char tokens[NTOKENS][TOKENLEN]; char tokens[NTOKENS][TOKENLEN];
int ntokens; int ntokens;
char *admonishment = "Try for fewer guesses next time!\n";
struct state { struct state {
time_t death; time_t death;
uint16_t answer; uint16_t answer;
@ -58,10 +60,14 @@ new_game(int sock, time_t now, struct sockaddr_in6 *from,
for (i = 0; i < 4; i += 1) { for (i = 0; i < 4; i += 1) {
s->answer = (s->answer << 4) | ((random() % 6) + 1); s->answer = (s->answer << 4) | ((random() % 6) + 1);
} }
g.token = s->answer;
break; break;
} }
} }
printf("=%02x\n", g.token);
if (g.offset < NSTATES) { if (g.offset < NSTATES) {
sendto(sock, &g, sizeof(g), 0, (struct sockaddr *) from, fromlen); sendto(sock, &g, sizeof(g), 0, (struct sockaddr *) from, fromlen);
} }
@ -112,7 +118,7 @@ loop(int sock)
new_game(sock, now, &from, fromlen); new_game(sock, now, &from, fromlen);
return; return;
} else { } else {
uint8_t reply; uint8_t reply = 0;
int i; int i;
for (i = 0; i < 4; i += 1) { for (i = 0; i < 4; i += 1) {
@ -127,16 +133,22 @@ loop(int sock)
reply += 0x01; reply += 0x01;
} }
} }
printf("%02x ? %02x\n", g.guess, reply);
if (reply == 0x40) { if (reply == 0x40) {
if (cur->guesses > ntokens) { char *r;
sendto(sock, tokens[cur->guesses],
strlen(tokens[cur->guesses]), 0, if (cur->guesses <= ntokens) {
(struct sockaddr *) &from, fromlen); r = tokens[cur->guesses - 1];
}
} else { } else {
sendto(sock, &reply, sizeof reply, 0, (struct sockaddr *) &from, r = admonishment;
fromlen); }
sendto(sock, r, strlen(r) - 1, 0,
(struct sockaddr *) &from, fromlen);
cur->death = 0;
} else {
sendto(sock, &reply, sizeof reply, 0,
(struct sockaddr *) &from, fromlen);
} }
} }
} }
@ -144,7 +156,6 @@ loop(int sock)
int int
main(int argc, char *argv[]) main(int argc, char *argv[])
{ {
long answer = 0;
int sock; int sock;
int i; int i;
struct in6_addr addr; struct in6_addr addr;
@ -180,10 +191,6 @@ main(int argc, char *argv[])
return EX_IOERR; return EX_IOERR;
} }
for (i = 0; i < 4; i += 1) {
answer = (answer << 4) | ((random() % 6) + 1);
}
while (1) { while (1) {
loop(sock); loop(sock);
} }

View File

@ -0,0 +1,10 @@
moo:1000000:xikov-fybir-zurox
moo:9:xukiv-hudyb-fesix
moo:8:xecoh-nyfyh-degix
moo:7:xihap-synik-gesix
moo:6:xegek-rulyz-polux
moo:5:xitiz-fokel-radix
moo:4:xuzif-gakit-fogyx
moo:3:xisav-nodob-besex
moo:2:xumol-peker-pibox
moo:1:xilom-zosyk-cavux

View File

@ -0,0 +1,91 @@
<!DOCTYPE html>
<html>
<head>
<title>Welcome</title>
<link rel="stylesheet" href="../ctf.css" type="text/css">
</head>
<body>
<h1>Moo.</h1>
<p>
You are trying to guess a 4-nybble sequence. Each nybble will have
either 1 or 2 bits set, and the highest bit will never be set. The
game server will tell you how many nybbles in each guess were correct,
and how many had one correct bit. It does not tell you which
positions.
</p>
<h2>The Cow Client</h2>
<p>
<a href="cowcli">Download the client</a>
</p>
<p>
The client connects to the Cow server running on the IPv6
address provided in argument 1. The client reads a guess
in the form of 4 ASCII numerals, and prints the number of
correct nybbles followed by the number of nybbles with one
correct bit.
</p>
<p>
Here is an example of a session:
</p>
<pre>
1111
12
2222
10
4444
02
4244
12
1244
22
1255
moo:xylep-radar-nanox
</pre>
<p>
You can use a program like <samp>socat</samp> to connect
the client to a logic program you write:
</p>
<pre>
socat EXEC:"./cowcli fd84:b410:3441::ec6" EXEC:./mysolution
</pre>
<p>
This will allow your program to read and write from stdio
of the client program.
</p>
<h2>The Cow Protocol</h2>
<p>
cowd runs on port 3782 on fd84:b410:3441::ec6.
</p>
<p>
The client always sends 6 octets. To request a new session, it sends
all zeroes. Otherwise it sends the 4-octet game identifier provided
by the server, concatenated with a 2-octet guess.
</p>
<p>
The server will respond with a new game identifier (4 octets) to a new
game request or if the game requested is too old. If a guess is
incorrect, the server will respond with either a 1-octet score in
which the high nybble is the number of correct nybbles in the guess,
and the low nybble is the number of nybbles in the guess with one
correct bit. If a guess is correct, the server will respond with a
token of length 5 octets or more.
</p>
<p>
There are multiple tokens, one per number of guesses used, up to
some maximum number of guesses defined per server instance.
</p>
</body>
</html>

View File

@ -61,11 +61,6 @@ main(int argc, char *argv[])
char needle[400]; char needle[400];
my_snprintf(needle, sizeof(needle), "%ld %s", points, answer); my_snprintf(needle, sizeof(needle), "%ld %s", points, answer);
{
FILE *f = fopen("/tmp/form", "w");
fprintf(f, "%s\n%s\n", answer, needle);
fclose(f);
}
if (! fgrepx(needle, if (! fgrepx(needle,
package_path("%s/answers.txt", category))) { package_path("%s/answers.txt", category))) {

View File

@ -1 +1 @@
10.0.0.28/24 fd84:b410:3441::b33b/64

View File

@ -2,7 +2,7 @@
exec 2>&1 exec 2>&1
read IP < ip.txt read IP < ip.txt
ip addr add $IP label eth0:rlyeh dev eth0 ip addr add $IP label eth0:rlyeh dev eth0 || true
dir=/var/lib/ctf/rlyeh dir=/var/lib/ctf/rlyeh
install -o nobody -d $dir install -o nobody -d $dir