Add in pwnables, start at octopus & tokencli

This commit is contained in:
Neale Pickett 2010-09-26 21:54:31 -06:00
parent e46bff58d0
commit 48caa26556
39 changed files with 1147 additions and 178 deletions

View File

@ -10,7 +10,12 @@ endef
include */*.mk
packages: $(addsuffix -package, $(PACKAGES))
packages: $(addsuffix .pkg, $(PACKAGES))
install: $(addsuffix -install, $(PACKAGES))
clean: $(addsuffix -clean, $(PACKAGES))
rm -rf build *.pkg
rm -rf build *.pkg *-install *-build
%.pkg: %-install
mksquashfs build/$* $*.pkg -all-root -noappend

59
common/arc4.c Normal file
View File

@ -0,0 +1,59 @@
#include <stdint.h>
#include <stdlib.h>
#include "arc4.h"
#define swap(a, b) do {int _swap=a; a=b, b=_swap;} while (0)
struct arc4_ctx {
uint8_t S[256];
uint8_t i;
uint8_t j;
};
void
arc4_init(struct arc4_ctx *ctx, uint8_t const *key, size_t keylen)
{
int i;
int j = 0;
for (i = 0; i < 256; i += 1) {
ctx->S[i] = i;
}
for (i = 0; i < 256; i += 1) {
j = (j + ctx->S[i] + key[i % keylen]) % 256;
swap(ctx->S[i], ctx->S[j]);
}
ctx->i = 0;
ctx->j = 0;
}
uint8_t
arc4_pad(struct arc4_ctx *ctx)
{
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(struct arc4_ctx *ctx,
uint8_t *obuf, uint8_t const *ibuf, size_t buflen)
{
size_t k;
for (k = 0; k < buflen; k += 1) {
obuf[k] = ibuf[k] ^ arc4_pad(ctx);
}
}
void
arc4_crypt_buffer(uint8_t const *key, size_t keylen,
uint8_t *buf, size_t buflen)
{
struct arc4_ctx ctx;
arc4_init(&ctx, key, keylen);
arc4_crypt(&ctx, buf, buf, buflen);
}

16
common/arc4.h Normal file
View File

@ -0,0 +1,16 @@
#ifndef __ARC4_H__
#define __ARC4_H__
#include <stdint.h>
#include <stdlib.h>
struct arc4_ctx;
void arc4_init(struct arc4_ctx *ctx, uint8_t const *key, size_t keylen);
uint8_t arc4_pad(struct arc4_ctx *ctx);
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);
#endif

97
common/token.c Normal file
View File

@ -0,0 +1,97 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdint.h>
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <unistd.h>
#include <values.h>
#ifndef CTF_BASE
#define CTF_BASE "/var/lib/ctf"
#endif
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
arc4_init(struct arc4_ctx *ctx, uint8_t const *key, size_t keylen)
{
int i;
int j = 0;
for (i = 0; i < 256; i += 1) {
ctx->S[i] = i;
}
for (i = 0; i < 256; i += 1) {
j = (j + ctx->S[i] + key[i % keylen]) % 256;
swap(ctx->S[i], ctx->S[j]);
}
ctx->i = 0;
ctx->j = 0;
}
void
arc4_crypt(struct arc4_ctx *ctx,
uint8_t *obuf, uint8_t const *ibuf, size_t buflen)
{
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;
}
void
arc4_crypt_buffer(uint8_t const *key, size_t keylen,
uint8_t *buf, size_t buflen)
{
struct arc4_ctx ctx;
arc4_init(&ctx, key, keylen);
arc4_crypt(&ctx, buf, buf, buflen);
}
ssize_t
read_token(char *name,
uint8_t const *key, size_t keylen,
char *buf, size_t buflen)
{
char path[PATH_MAX];
int pathlen;
int fd;
ssize_t ret;
pathlen = snprintf(path, sizeof(path) - 1,
CTF_BASE "/tokens/%s", name);
path[pathlen] = '\0';
fd = open(path, O_RDONLY);
if (-1 == fd) return -1;
ret = read(fd, buf, buflen);
close(fd);
if (-1 != ret) {
arc4_crypt_buffer(key, keylen, (uint8_t *)buf, (size_t)ret);
}
return ret;
}

21
common/token.h Normal file
View File

@ -0,0 +1,21 @@
#ifndef __TOKEN_H__
#define __TOKEN_H__
#include <unistd.h>
#include <stdlib.h>
#include <stdint.h>
/* 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(char *name,
uint8_t const *key, size_t keylen,
char *buf, size_t buflen);
#endif

View File

@ -1,9 +1,7 @@
MCP_PKGDIR = build/mcp
MCP_PACKAGE = mcp.pkg
mcp-package: $(MCP_PACKAGE)
$(MCP_PACKAGE): mcp-build
mcp-install: mcp-build
mkdir -p $(MCP_PKGDIR)
cp mcp/setup $(MCP_PKGDIR)
@ -20,8 +18,7 @@ $(MCP_PACKAGE): mcp-build
cp mcp/src/puzzler.cgi $(MCP_PKGDIR)/www/
cp mcp/src/claim.cgi $(MCP_PKGDIR)/www/
mksquashfs $(MCP_PKGDIR) $(MCP_PACKAGE) -all-root -noappend
touch $@
mcp-test: mcp-build
mcp/test.sh

View File

@ -1,59 +0,0 @@
#include <stdint.h>
#include <stdlib.h>
#include "arc4.h"
#define swap(a, b) do {int _swap=a; a=b, b=_swap;} while (0)
struct arc4_ctx {
uint8_t S[256];
uint8_t i;
uint8_t j;
};
void
arc4_init(struct arc4_ctx *ctx, uint8_t const *key, size_t keylen)
{
int i;
int j = 0;
for (i = 0; i < 256; i += 1) {
ctx->S[i] = i;
}
for (i = 0; i < 256; i += 1) {
j = (j + ctx->S[i] + key[i % keylen]) % 256;
swap(ctx->S[i], ctx->S[j]);
}
ctx->i = 0;
ctx->j = 0;
}
uint8_t
arc4_pad(struct arc4_ctx *ctx)
{
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(struct arc4_ctx *ctx,
uint8_t *obuf, uint8_t const *ibuf, size_t buflen)
{
size_t k;
for (k = 0; k < buflen; k += 1) {
obuf[k] = ibuf[k] ^ arc4_pad(ctx);
}
}
void
arc4_crypt_buffer(uint8_t const *key, size_t keylen,
uint8_t *buf, size_t buflen)
{
struct arc4_ctx ctx;
arc4_init(&ctx, key, keylen);
arc4_crypt(&ctx, buf, buf, buflen);
}

1
mcp/src/arc4.c Symbolic link
View File

@ -0,0 +1 @@
../../common/arc4.c

View File

@ -1,16 +0,0 @@
#ifndef __ARC4_H__
#define __ARC4_H__
#include <stdint.h>
#include <stdlib.h>
struct arc4_ctx;
void arc4_init(struct arc4_ctx *ctx, uint8_t const *key, size_t keylen);
uint8_t arc4_pad(struct arc4_ctx *ctx);
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);
#endif

1
mcp/src/arc4.h Symbolic link
View File

@ -0,0 +1 @@
../../common/arc4.h

View File

@ -1,92 +0,0 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <sysexits.h>
#include <stdio.h>
#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 filenames.\n");
fprintf(stderr, "Tokens are written to file descriptor 3.\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;
}

1
mcp/src/tokencli.c Symbolic link
View File

@ -0,0 +1 @@
../../tokencli/src/tokencli.c

18
octopus/octopus.mk Normal file
View File

@ -0,0 +1,18 @@
OCTOPUS_PKGDIR = build/octopus
OCTOPUS_PACKAGE = octopus.pkg
octopus-install: octopus-build
mkdir -p $(OCTOPUS_PKGDIR)/bin/
$(call COPYTREE, octopus/service, $(OCTOPUS_PKGDIR)/service)
cp octopus/src/octopus $(OCTOPUS_PKGDIR)/bin/
octopus-clean:
rm -rf $(OCTOPUS_PKGDIR) $(OCTOPUS_PACKAGE)
$(MAKE) -C octopus/src clean
octopus-build:
$(MAKE) -C octopus/src build
PACKAGES += octopus

View File

@ -0,0 +1,3 @@
#! /bin/sh
exec logger -t octopus

4
octopus/service/octopus/run Executable file
View File

@ -0,0 +1,4 @@
#! /bin/sh
exec 2>&1
exec /opt/octopus/bin/octopus

3
octopus/setup Executable file
View File

@ -0,0 +1,3 @@
#! /bin/sh
mkdir -p /var/lib/ctf/tokens

7
octopus/src/Makefile Normal file
View File

@ -0,0 +1,7 @@
# Octopus / Some kind of octopus / Tearing my shell apart / Letting the
# sea get in / You make my insides outside
octopus: octopus.o token.o
clean:
rm -f octopus *.o

373
octopus/src/octopus.c Normal file
View File

@ -0,0 +1,373 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sysexits.h>
#include <errno.h>
#include <time.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include "token.h"
#define OUTPUT_MAX 1024
#define INPUT_MAX 1024
#ifndef max
#define max(a,b) (((a)>(b))?(a):(b))
#endif
uint8_t const key[] = {0x7d, 0x47, 0x84, 0x28,
0x09, 0x87, 0xb5, 0xd2,
0xd8, 0xab, 0x1c, 0xf3,
0xf2, 0x96, 0xd6, 0x68};
char const octopus[] =
(" ___\n"
" .-' `'.\n"
" / \\\n"
" | ;\n"
" | | ___.--,\n"
" _.._ |8) ~ (8) | _.---'`__.-( (_.\n"
" __.--'`_.. '.__.\\ '--. \\_.-' ,.--'` `""`\n"
" ( ,.--'` ',__ /./; ;, '.__.'` __\n"
" _`) ) .---.__.' / | |\\ \\__..--\"\" \"\"\"--.,_\n"
" `---' .'.''-._.-'`_./ /\\ '. \\ _.-~~~````~~~-._`-.__.'\n"
" | | .' _.-' | | \\ \\ '. `~---`\n"
" \\ \\/ .' \\ \\ '. '-._)\n"
" \\/ / \\ \\ `=.__`~-.\n"
" jgs / /\\ `) ) / / `\"\".`\\\n"
" , _.-'.'\\ \\ / / ( ( / /\n"
" `--~` ) ) .-'.' '.'. | (\n"
" (/` ( (` ) ) '-;\n"
" ` '-; (-'\n"
);
const char *friends[8] = {
("Help Olive Octopus visit all 8 of her friends to receive a prize!\n"
"Hurry though, things change quickly!\n"
"Next friend: %08o\n"
"%s"
),
("Thanks for stopping by, Olive! Good luck finding that prize!\n"
"Next friend: %08o\n"
" ,__\n"
" | `'.\n"
"__ |`-._/_.:---`-.._\n"
"\\='. _/..--'`__ `'-._\n"
" \\- '-.--\"` === / o `',\n"
" )= ( .--_ | _.'\n"
" /_=.'-._ {=_-_ | .--`-.\n"
"/_.' `\\`'-._ '-= \\ _.'\n"
" jgs ) _.-'`'-.. _..-'`\n"
" /_.' `/\";';`|\n"
" \\` .'/\n"
" '--'\n"
),
("Snap, snap! Good luck on your quest, Olive!\n"
"Next friend: %08o\n"
" .\"\".-._.-.\"\".\n"
" | \\ | / |\n"
" \\ \\.T./ /\n"
" '-./ \\.-'\n"
" / \\\n"
" ; ;\n"
" | |\n"
" | |\n"
" / \\\n"
" | . |\n"
" __.| : |.__\n"
" .-'` | : | `'-.\n"
" /` .\"\\ 0 : 0 /\". `\\\n"
" | _/ './ : \\.' \\_ |\n"
" | / /`\"\"\"`\\ \\ |\n"
" \\ \\ .-' '._ / /\n"
" jgs '-._\\ /_.-'\n"
),
("Nice talking with you, Olive. I'd best get back to my babies now!\n"
"Next friend: %08o\n"
" , ,\n"
" \\:.|`._\n"
" /\\/;.:':::;;;._\n"
" < .' ':::;(\n"
" < ' _ '::;>\n"
" \\ (9) _ :::;(\n"
" | / \\ ::;`>\n"
" | / | :;(\n"
" | ( <=- .::;>\n"
" ( a) )=- .::;(\n"
" '-' <=- .::;>\n"
" )==- ::::( ,\n"
" <==- :::(,-'(\n"
" )=- ':: _.->\n"
" <==- ':.' _(\n"
" <==- .:'_ (\n"
" )==- .::' '->\n"
" <=- .:;(`'.(\n"
" `) ':;> `\n"
" .-. < :;(\n"
" <`.':\\ ) :;>\n"
" < :/<_/ < .:;>\n"
" < '`---'` .::(`\n"
" jgs < .:;>'\n"
" `-..:::-'`\n"
),
("Spshhh! Good to see you, Olive! You're on the right track!\n"
"Next friend: %08o\n"
" ,_\n"
" \\::,\n"
" |::::\\\n"
" |:::::\\\n"
" __/:::::::\\,____\n"
" _.-::::::::::::::::::::==..,____\n"
" .-::::::::::::::::::::::::::::::::::::.,__\n"
" .:::::::::::::::::::::::::::::::::::::::::::::)\n"
" .:::::'```'-::::::::::::::::::::::(__,__`)::::-'\n"
" .;;;;;;::. ':::::::::::::::::::-:::::@::-'\"\"-,\n"
" .------:::::::::::' '-::::::::::' / `'--'\"\"\"\".-'\n"
"/:::::::::/:::/` _,..-----.,__ `''''`/ ;__,..--''--'`\n"
"`'--::::::::::|-'` `'---'| |\n"
" `\\::::\\ \\ /\n"
" |:::::| '-'\n"
" \\::::|\n"
" jgs `\\::|\n"
" \\/\n"
),
("You're getting close, Olive!\n"
"Next friend: %08o\n"
" .-------------'```'----......,,__ _,\n"
" | `'`'`'`'-.,.__ .'(\n"
" | `'--._.' )\n"
" | `'-.<\n"
" \\ .-'`'-. -. `\\\n"
" \\ -.o_. _ _,-'`\\ |\n"
" ``````''--.._.-=-._ .' \\ _,,--'` `-._(\n"
" (^^^^^^^^`___ '-. | \\ __,,,...--' `\n"
" ````````` `'--..___\\ |`\n"
" jgs `-.,'\n"
),
("Hi, Olive! Not much further now!\n"
"Next friend: %08o\n"
" , ,\n"
" /(_, ,_)\\\n"
" \\ _/ \\_ /\n"
" // \\\\\n"
" \\\\ (@)(@) //\n"
" \\'=\"==\"='/\n"
" ,===/ \\===,\n"
" \",===\\ /===,\"\n"
" \" ,==='------'===, \"\n"
" jgs \" \"\n"
),
("Aha! You found me!\n"
"Prize: %.*s\n"
" (\\.-./)\n"
" / \\\n"
" .' : '.\n"
" _.-'` ' `'-._\n"
" .-' : '-.\n"
" ,'_.._ . _.._',\n"
" '` `'-. ' .-'` `'\n"
" '. : .'\n"
" \\_. ._/\n"
" \\ |^|\n"
" | jgs | ;\n"
" \\'.___.' /\n"
" '-....-'\n")
};
const char invalid[] = "Who are you? Go away!\n";
#ifdef EASY
# define PORTS 15
#else
# define PORTS 8
#endif
struct bound_port {
int fd;
char output[OUTPUT_MAX];
size_t output_len;
} bound_ports[PORTS];
int
bind_port(int fd, uint16_t port) {
struct sockaddr_in addr;
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));
}
int
rebind()
{
static int offset = 0;
char token[200];
size_t tokenlen;
int i;
tokenlen = read_token("octopus",
key, sizeof(key),
token, sizeof(token));
if (-1 == tokenlen) {
return -1;
}
for (i = 1; i < 8; i += 1) {
int ret;
int last_guy;
in_port_t port;
if (-1 != bound_ports[i + offset].fd) {
while (-1 == close(bound_ports[i + offset].fd)) {
if (errno != EINTR) {
return -1;
}
}
}
/* Bind to a port */
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);
} while (-1 == ret);
/* Set the last guy's port number */
last_guy = i + offset - 1;
switch (i) {
case 1:
/* Always change the port 8888 one */
last_guy = 0;
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
bound_ports[last_guy].output_len =
snprintf(bound_ports[last_guy].output, OUTPUT_MAX,
friends[i - 1], port, octopus);
break;
}
}
bound_ports[7 + offset].output_len =
snprintf(bound_ports[7 + offset].output, OUTPUT_MAX,
friends[7], tokenlen, token);
if (offset == 0) {
offset = PORTS - 8;
} else {
offset = 0;
}
return 0;
}
void
do_io(int which)
{
struct bound_port *bp = &bound_ports[which];
char input[INPUT_MAX];
ssize_t inlen;
struct sockaddr from;
socklen_t fromlen = sizeof(from);
inlen = recvfrom(bp->fd, input, INPUT_MAX, 0,
&from, &fromlen);
if (-1 == inlen) {
/* Well don't that just beat all. */
return;
}
if (which > 0) {
if ((inlen != sizeof(octopus) - 1) ||
(0 != memcmp(input, octopus, inlen))) {
/* Didn't send the octopus */
sendto(bp->fd, invalid, sizeof(invalid), 0,
&from, fromlen);
return;
}
}
sendto(bp->fd, bp->output, bp->output_len, 0,
&from, fromlen);
}
int
loop()
{
int i;
int nfds = 0;
fd_set rfds;
struct timeval timeout;
timeout.tv_sec = 1;
timeout.tv_usec = 0;
FD_ZERO(&rfds);
for (i = 0; i < PORTS; i += 1) {
nfds = max(nfds, bound_ports[i].fd);
FD_SET(bound_ports[i].fd, &rfds);
}
/* Wait forever. There's no need to switch ports if nobody's doing
anything. */
while (-1 == select(nfds+1, &rfds, NULL, NULL, &timeout)) {
if (EINTR == errno) {
continue;
}
return 0;
}
for (i = 0; i < PORTS; i += 1) {
if (FD_ISSET(bound_ports[i].fd, &rfds)) {
do_io(i);
}
}
return 1;
}
int
main(int argc, char *argv[])
{
int ret;
int i;
time_t last = time(NULL);
/* The random seed isn't super important here. */
srand(8);
bound_ports[0].fd = socket(PF_INET, SOCK_DGRAM, 0);
ret = bind_port(bound_ports[0].fd, 8888);
if (-1 == ret) {
perror("bind port 8888");
return EX_IOERR;
}
for (i = 1; i < PORTS; i += 1) {
bound_ports[i].fd = -1;
}
if (-1 == rebind()) {
perror("initial binding");
return EX_IOERR;
}
while (loop()) {
time_t now = time(NULL);
if (last + 4 < now) {
last = now;
if (-1 == rebind()) break;
}
}
perror("main loop");
return EX_IOERR;
}

1
octopus/src/token.c Symbolic link
View File

@ -0,0 +1 @@
../../common/token.c

1
octopus/src/token.h Symbolic link
View File

@ -0,0 +1 @@
../../common/token.h

View File

@ -3,12 +3,17 @@ PUZZLES += forensics hackme net-re sequence skynet webapp
-include puzzles/*/*.mk
puzzles/%-package:
puzzles/%-install:
mkdir -p build/$*
puzzles/mkpuzzles puzzles/$* build/$*
mksquashfs build/$* $*.pkg -all-root -noappend
touch $@
puzzles/%-clean:
rm -rf build/$*
rm -rf build/$* puzzles/$*-install
PACKAGES += $(addprefix puzzles/, $(PUZZLES))
%.pkg: puzzles/%-install
mksquashfs build/$* $*.pkg -all-root -noappend
packages: $(addsuffix .pkg, $(PUZZLES))
install: $(patsubst %, puzzles/%-install, $(PUZZLES))
clean: $(patsubst %, puzzles/%-clean, $(PUZZLES))

21
pwnables/pwnables.mk Normal file
View File

@ -0,0 +1,21 @@
PWNABLES_PKGDIR = build/pwnables
PWNABLES_PACKAGE = pwnables.pkg
pwnables-install: pwnables-build
mkdir -p $(PWNABLES_PKGDIR)
cp pwnables/setup $(PWNABLES_PKGDIR)
mkdir -p $(PWNABLES_PKGDIR)/bin/
$(MAKE) -C pwnables/src install DESTDIR=$(CURDIR)/$(PWNABLES_PKGDIR)
$(call COPYTREE, pwnables/service, $(PWNABLES_PKGDIR)/service)
pwnables-clean:
rm -rf $(PWNABLES_PKGDIR) $(PWNABLES_PACKAGE)
$(MAKE) -C pwnables/src clean
pwnables-build:
$(MAKE) -C pwnables/src build
PACKAGES += pwnables

View File

@ -0,0 +1,3 @@
#! /bin/sh
exec logger -t pwnables

View File

@ -0,0 +1,4 @@
.::7777::-.
/:'////' `::>/|/
.', |||| `/( e\
-==~-'`-Xm````-mr' `-_\

View File

@ -0,0 +1,4 @@
#! /bin/sh
[ -f motd ] && cat motd
exec chroot /mnt/pwnables-root login -f alice

3
pwnables/service/pwnables/run Executable file
View File

@ -0,0 +1,3 @@
#! /bin/sh -e
exec tcpsvd -C 5:"Let's not be greedy" 0 23 /sbin/telnetd -l ./pwnie

35
pwnables/setup Executable file
View File

@ -0,0 +1,35 @@
#! /bin/sh
if [ ! -d /opt/mcp ]; then
hostname pwnables
fi
# Set up a chroot environment by duplicating the base
# image
if [ ! -x /mnt/pwnables-root/bin/busybox ]; then
mkdir -p /mnt/pwnables-root
mount -o bind / /mnt/pwnables-root
mount -t tmpfs -o size=5m,mode=0755 pwnables-var /mnt/pwnables-root/var
mount -t tmpfs -o size=15k pwnables-tmp /mnt/pwnables-root/tmp
mount -t tmpfs -o size=5m pwnables-home /mnt/pwnables-root/home
# Make some skeleton junk
install -o root -m 0755 -d /mnt/pwnables-root/var/lib
install -o root -m 0755 -d /mnt/pwnables-root/var/log
install -o root -m 0755 -d /mnt/pwnables-root/var/spool
install -o root -m 0755 -d /mnt/pwnables-root/var/cache
install -o root -m 0777 -d /mnt/pwnables-root/var/run
install -o root -m 0777 -d /mnt/pwnables-root/var/cache
install -o root -d /mnt/pwnables-root/home/alice/
install -o root -m 0111 bin/* /mnt/pwnables-root/home/alice/
# ltrace needs to read the binary
chmod +r /mnt/pwnables-root/home/alice/ltraceme
# strace needs to be suid
chown bob /mnt/pwnables-root/home/alice/straceme
chmod 04511 /mnt/pwnables-root/home/alice/straceme
fi
cp -r service/* /var/service/

18
pwnables/src/Makefile Normal file
View File

@ -0,0 +1,18 @@
CFLAGS = -Wall -Werror
TARGETS = gimmie ltraceme straceme killme
all: build
build: $(TARGETS)
gimmie: gimmie.o token.o
octopus: octopus.o token.o
ltraceme: ltraceme.o token.o
straceme: straceme.o token.o
killme: killme.o token.o
install: $(TARGETS)
install -m 0755 $(TARGETS) $(DESTDIR)/bin
clean:
rm -f *.o $(TARGETS)

49
pwnables/src/arc4.c Normal file
View File

@ -0,0 +1,49 @@
#include <stdint.h>
#include <stdio.h>
#include <sysexits.h>
#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;
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);
}
if (0 == keylen) {
fprintf(stderr, "Usage: %s [KEYFILE] <PLAINTEXT\n", argv[0]);
fprintf(stderr, "\n");
fprintf(stderr, "You can also pass in the key on fd 3; omit\n");
fprintf(stderr, "KEYFILE in this case.\n");
return EX_IOERR;
}
arc4_init(&ctx, key, (size_t)keylen);
}
/* Encrypt */
while (1) {
int c = getchar();
if (EOF == c) break;
putchar(c ^ arc4_pad(&ctx));
}
return 0;
}

26
pwnables/src/gimmie.c Normal file
View File

@ -0,0 +1,26 @@
#include <unistd.h>
#include "token.h"
uint8_t const key[] = {0x5f, 0x64, 0x13, 0x29,
0x2e, 0x46, 0x76, 0xcd,
0x65, 0xff, 0xe8, 0x03,
0xa4, 0xa9, 0x4f, 0xd9};
int
main(int argc, char *argv[])
{
char token[200];
ssize_t tokenlen;
tokenlen = read_token("gimmie",
key, sizeof(key),
token, sizeof(token) - 1);
if (-1 == tokenlen) {
return 69;
}
token[tokenlen++] = '\n';
write(1, token, tokenlen);
return 0;
}

77
pwnables/src/killme.c Normal file
View File

@ -0,0 +1,77 @@
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <time.h>
#include "token.h"
#define SIGS 20
uint8_t const key[] = {0x51, 0x91, 0x6d, 0x81,
0x14, 0x21, 0xf8, 0x95,
0xb8, 0x09, 0x87, 0xa6,
0xa8, 0xb0, 0xa0, 0x46};
int lastsig;
void
handler(int signum)
{
lastsig = signum;
}
int
main(int argc, char *argv[])
{
int i;
{
/* Seed random number generator */
FILE *f;
int seed;
f = fopen("/dev/urandom", "r");
if (f) {
fread(&seed, sizeof(seed), 1, f);
srandom(seed);
} else {
srandom(getpid() * time(NULL));
}
}
for (i = 1; i < 8; i += 1) {
signal(i, handler);
}
for (i = 0; i < SIGS; i += 1) {
int desired = (random() % 7) + 1;
lastsig = 0;
printf("%d\n", desired);
fflush(stdout);
if (i == 0) {
sleep(5);
} else {
sleep(1);
}
if (0 == lastsig) {
printf("Too slow.\n");
return 1;
}
if (lastsig != desired) {
printf("Wrong one.\n");
return 1;
}
}
{
char token[200];
size_t tokenlen;
tokenlen = read_token("killme",
key, sizeof(key),
token, sizeof(token) - 1);
}
return 0;
}

60
pwnables/src/ltraceme.c Normal file
View File

@ -0,0 +1,60 @@
#include <stdio.h>
#include <time.h>
#include <stdint.h>
#include <string.h>
#include "token.h"
/* This hopefully requires an LD_PRELOAD */
uint8_t const key[] = {0x94, 0xf2, 0x92, 0x45,
0x12, 0x44, 0x80, 0xe1,
0x95, 0x64, 0xcd, 0xe4,
0xff, 0x0a, 0x00, 0x10};
int
main(int argc, char *argv[])
{
char token[200];
size_t tokenlen;
/* Do some bullshit. Override with:
*
* void strcmp(char *a, char *b)
* {
* return 0;
* }
*/
{
FILE *f = fopen("/dev/urandom", "r");
unsigned int seed;
char seed_str[50];
printf("Checking credentials...\n");
fread(&seed, sizeof(seed), 1, f);
sprintf(seed_str, "%d", seed);
if ((argc != 2) || strcmp(seed_str, argv[1])) {
printf("Ah ah ah! You didn't say the magic word!\n");
return 1;
}
}
tokenlen = read_token("ltraceme",
key, sizeof(key),
token, sizeof(token) - 1);
if (-1 == tokenlen) {
printf("Unable to read token.\n");
return 1;
}
token[tokenlen++] = '\0';
/* You could override this with:
*
* void printf(char *fmt, size_t len, char *buf)
* {
* if (fmt[0] == 'T') write(1, buf, len);
* }
*/
printf("Token length %u at %p.\n", tokenlen, token);
return 0;
}

91
pwnables/src/straceme.c Normal file
View File

@ -0,0 +1,91 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdint.h>
#include <stdarg.h>
#include <sysexits.h>
#include <stdio.h>
#include <ctype.h>
#include "token.h"
uint8_t const key[] = {0x30, 0x00, 0x55, 0x0f,
0xc2, 0xf6, 0x52, 0x2a,
0x31, 0xfd, 0x00, 0x92,
0x9d, 0x49, 0x24, 0xce};
int
main(int argc, char *argv[])
{
/* Check argv[1].
*
* If no args, argv[1] will be NULL, which causes a segfault.
* This is what we want.
*
* To pass this, run ./straceme $$.
* But you have to do it from a shell script, because if you run
* strace ./straceme $$
* getppid() will return the PID of strace!
*/
if (getppid() != atoi(argv[1])) {
write(2, "argv[1] incorrect\n", 18);
return EX_USAGE;
}
/* Read an rc file.
*
* To pass this, set $HOME to someplace you have access.
*/
{
int fd;
char fn[128];
char bs[1000];
int len;
len = snprintf(fn, sizeof(fn) - 1, "%s/.stracemerc", getenv("HOME"));
if (len < 0) {
len = 0;
}
fn[len] = '\0';
if (-1 == (fd = open(fn, O_RDONLY))) {
fd = open("/etc/stracemerc", O_RDONLY);
}
if (-1 == fd) {
return EX_NOINPUT;
}
/* We don't actually care about contents */
read(fd, bs, sizeof(bs));
close(fd);
}
/* Read in category name from fd 2 (stderr!)
*
* echo -n straceme > foo.txt
* ./straceme $$ 2< foo.txt
*/
{
char cat[50];
int catlen;
char token[200];
size_t tokenlen;
int i;
catlen = read(2, cat, sizeof(cat) - 1);
for (i = 0; i < catlen; i += 1) {
if (! isalnum(cat[i])) break;
}
cat[i] = '\0';
tokenlen = read_token(cat,
key, sizeof(key),
token, sizeof(token));
if (-1 == tokenlen) {
return EX_NOINPUT;
}
write(1, token, tokenlen);
}
return 0;
}

1
pwnables/src/token.c Symbolic link
View File

@ -0,0 +1 @@
../../common/token.c

1
pwnables/src/token.h Symbolic link
View File

@ -0,0 +1 @@
../../common/token.h

View File

@ -0,0 +1,3 @@
#! /bin/sh
exec logger -t tokencli

11
tokencli/service/tokencli/run Executable file
View File

@ -0,0 +1,11 @@
#! /bin/sh
exec 2>&1
while true; do
for fn in /opt/*/*.tokenkey; do
cat=$(basename $fn .tokenkey)
echo "XXX: not implemented yet"
done
sleep 60
done

4
tokencli/src/Makefile Normal file
View File

@ -0,0 +1,4 @@
tokencli: tokencli.o arc4.o
clean:
rm *.o tokencli

1
tokencli/src/arc4.c Symbolic link
View File

@ -0,0 +1 @@
../../common/arc4.c

1
tokencli/src/arc4.h Symbolic link
View File

@ -0,0 +1 @@
../../common/arc4.h

92
tokencli/src/tokencli.c Normal file
View File

@ -0,0 +1,92 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <sysexits.h>
#include <stdio.h>
#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 filenames.\n");
fprintf(stderr, "Tokens are written to file descriptor 3.\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;
}

18
tokencli/tokencli.mk Normal file
View File

@ -0,0 +1,18 @@
TOKENCLI_PKGDIR = build/tokencli
TOKENCLI_PACKAGE = tokencli.pkg
tokencli-install: tokencli-build
mkdir -p $(TOKENCLI_PKGDIR)/bin/
$(call COPYTREE, tokencli/service, $(TOKENCLI_PKGDIR)/service)
cp tokencli/src/tokencli $(TOKENCLI_PKGDIR)/bin/
tokencli-clean:
rm -rf $(TOKENCLI_PKGDIR) $(TOKENCLI_PACKAGE)
$(MAKE) -C tokencli/src clean
tokencli-build:
$(MAKE) -C tokencli/src build
PACKAGES += tokencli