mirror of https://github.com/dirtbags/moth.git
Merge branch 'master' of fozzie.woozle.org:projects/ctf
This commit is contained in:
commit
f7e5a5c3b3
|
@ -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,
|
||||||
|
|
||||||
--
|
--
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
After Width: | Height: | Size: 110 KiB |
|
@ -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
|
|
@ -0,0 +1,4 @@
|
||||||
|
#! /bin/sh
|
||||||
|
|
||||||
|
read IP < ip.txt
|
||||||
|
ip addr del $IP dev eth0
|
|
@ -0,0 +1 @@
|
||||||
|
fd84:b410:3441::ec6/64
|
|
@ -0,0 +1,3 @@
|
||||||
|
#! /bin/sh
|
||||||
|
|
||||||
|
exec svlogd -tt $PWD
|
|
@ -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
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
|
@ -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>
|
|
@ -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))) {
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
10.0.0.28/24
|
fd84:b410:3441::b33b/64
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue