Writeup — Anthem (TryHackMe) OS: Windows Server 2019 (build 17763, Umbraco 7.15.4 + Articulate) Difficulty: Easy Date: 9 September 2026 --- ## Summary Windows Server 2019 machine, not domain-joined, with only two ports exposed, a webserver on 80 and RDP on 3389. No exploit, no vulnerable service: the room is entirely about observation. The site is an Umbraco blog with the Articulate plugin, and it hides four flags in places you don't see by opening the page in a browser, all inside the HTML source or in secondary profile fields. The robots.txt contains a password left at the top of the file outside any valid syntax. the corresponding username isn't the one signed at the bottom of the posts, which is the real author of the poem quoted, but the subject of the poem itself, reduced to initials following the scheme of the email found in the other post. From RDP as a standard user the filesystem is almost empty, except for an unreadable backup file: changing its ACLs from the Windows interface reveals the Administrator's password, and from there the root flag Chain: nmap → 80 and 3389 → HTML source → Umbraco/Articulate + first flag in the search placeholder → robots.txt → password → RSS for the real post links → meta og:description → two flags → author page → fourth flag → poem Solomon Grundy → username SG → RDP → user.txt → C:\backup\restore.txt unreadable → ACLs modified → Administrator password → RDP as Administrator → root.txt. --- ## additional tools and methodology an llm was used during the session: for looking up CVE details, interpreting raw output, suggesting unexplored vectors when stuck and detailed explanation of technical concepts. the execution and the operational decisions were mine. the writeup was written by me and later cleaned up with the same tool. the connection between the poem and the username was suggested by the chatbot after I had exhausted about ten formats based on the wrong author. one flag, the last one, I recovered from a public writeup after the machine expired: I write it here because it's the only step of this room I didn't execute personally. --- ## Preface room done from my virtualised Kali, with the VPN already up from the previous session on Blueprint. technically there's nothing difficult, but it's the room where I lost the most time on a single detail: the RDP username. the password is found in the first two minutes, the username took about fifteen attempts on three different people before realising I was looking at the wrong name the second thing that slowed me down is that the flags turn up in places disconnected from each other, meta tags, the placeholder of a search field, profile fields, and when you find them you have no way of knowing which room question they correspond to. I collected them all first and matched them afterwards,by trial and error. the machine expired right after reading the root flag and without a subscription it can't be redeployed, so the final part verifying Administrator privileges was left unexecuted. --- ## Phase 1 — Reconnaissance same scanning scheme as the previous room: IP=10.112.170.81; sudo nmap -sS -Pn -p- --min-rate 5000 -oN anthem_full.txt IP && sudo nmap -sV -sC -p (grep -oP '^\d+(?=/tcp\s+open)' anthem_full.txt | paste -sd,) -oN anthem_svc.txt $IP Not shown: 65533 filtered tcp ports (no-response) 80/tcp open http 3389/tcp open ms-wbt-server the second scan died immediately with "Host seems down": in the chained command I had left the -Pn only in the first one, and on a host that filters everything the preliminary ping fails. relaunched by hand: sudo nmap -sV -sC -Pn -p80,3389 -oN anthem_svc.txt 10.112.170.81 80/tcp open http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP) 3389/tcp open ms-wbt-server Microsoft Terminal Services | rdp-ntlm-info: | Target_Name: WIN-LU09299160F | NetBIOS_Domain_Name: WIN-LU09299160F | DNS_Computer_Name: WIN-LU09299160F | Product_Version: 10.0.17763 Windows Server 2019, hostname WIN-LU09299160F, and the fact that the NetBIOS domain and the machine name coincide confirms it isn't domain-joined: the accounts are local. all the other 65533 ports are filtered, not closed, so there's a firewall that drops rather than refuses . with only two ports and no vulnerable version in sight, the webserver is the only surface to work. --- ## Phase 2 — Homepage source instead of opening the site in a browser I read the raw HTML directly, which is faster and also shows what the browser doesn't render: curl -s http://10.112.170.81/ | head -60 from the head of the page comes everything needed to frame the application: invisible when looking at the page, because the text is preceded by about fifty spaces and gets truncated by the field. it's only visible in the source. --- ## Phase 3 — robots.txt curl -s http://10.112.170.81/robots.txt UmbracoIsTheBest! Use for all search robots User-agent: * Define the directories not to crawl Disallow: /bin/ Disallow: /config/ Disallow: /umbraco/ Disallow: /umbraco_client/ robots.txt is a text file that sits in the root of any site and serves to tell search engine crawlers which folders not to index. it isn't an application endpoint and it isn't a protection: anyone can read it, and precisely because it lists the folders the owner would like to hide it often reveals the administrative paths. it should always be read, right after the homepage, together with sitemap.xml here it confirms /umbraco/ as the administration panel, but above all it has at the top a line that has nothing to do with the file's syntax: UmbracoIsTheBest!. it's a password, left there by someone and never removed. --- ## Phase 4 — The posts and the hunt for the author I have the password, the username is missing. the blog posts are two, "We are hiring" and "A cheers to our IT department". first mistake: I tried to guess the post URLs with the date scheme typical of WordPress (/2021/04/we-are-hiring/), and Articulate always answered me with the archive page instead of the single post, making me believe for a couple of attempts that I was reading the right content. the real links are in the RSS feed, which the blog exposes and which nobody was stopping me from reading: curl -s http://10.112.170.81/rss | grep -oP '(?<=)[^<]+' http://10.112.170.81/ http://10.112.170.81/archive/we-are-hiring/ http://10.112.170.81/archive/a-cheers-to-our-it-department/ the second post contains the poem: curl -s http://10.112.170.81/archive/a-cheers-to-our-it-department/ | sed -e 's/<[^>]>//g' | grep -v '^\s$' | head -40 During our hard times our beloved admin managed to save our business by redesigning the entire website. As we all around here knows how much I love writing poems I decided to write one about him: Born on a Monday,Christened on Tuesday,Married on Wednesday,Took ill on Thursday, Grew worse on Friday,Died on Saturday,Buried on Sunday.That was the end... Author James Orchard Halliwell the first post gives the other piece: If you have an interest in being a part of the movement send me your CV at JD@anthem.com Author Jane Doe so two names and an email format. from here a long series of failed attempts begins,first with xfreerdp: xfreerdp3 /v:10.112.170.81 /u:jhalliwell /p:'UmbracoIsTheBest!' /cert:ignore +clipboard /dynamic-resolution [ERROR][com.freerdp.core.rdp] - CONNECTION_STATE_NLA - nla_recv_pdu() fail xfreerdp3 is the command-line RDP client for Linux, the equivalent of Windows' Remote Desktop Connection. /u: is the local user, /p: the password found in robots.txt, /cert:ignore accepts the machine's self-signed certificate. every attempt however requires waiting for the complete handshake, and it's slow. to speed things up I switch to NetExec, which tests credentials against the protocol without opening the graphical session: nxc rdp 10.112.170.81 -u jane.doe -p 'UmbracoIsTheBest!' RDP 10.112.170.81 3389 WIN-LU09299160F [*] Windows 10 or Windows Server 2016 Build 17763 (name:WIN-LU09299160F) (domain:WIN-LU09299160F) (nla:False) RDP 10.112.170.81 3389 WIN-LU09299160F [-] WIN-LU09299160F\jane.doe:UmbracoIsTheBest! (STATUS_LOGON_FAILURE) nla:False is useful information in itself: network level authentication is disabled, so authentication happens after establishing the session and not before. STATUS_LOGON_FAILURE however doesn't distinguish between a non-existent user and a wrong password, so it neither confirms nor rules out the name. with a loop you test nine formats in a few seconds: for u in JD jd jane janedoe j.doe doe UmbracoAdmin admin administrator; do nxc rdp 10.112.170.81 -u $u -p 'UmbracoIsTheBest!'; done all STATUS_LOGON_FAILURE. including administrator, which with that password doesn't get in. the reasoning that unblocks the situation: the post says the poem is dedicated to the admin, and the signature at the bottom of the page is of whoever wrote the text, not of whoever is its subject. the poem is Solomon Grundy, an English nursery rhyme collected and published by James Orchard Halliwell himself. the admin is therefore called Solomon Grundy, and the email format of the other post (JD@anthem.com for Jane Doe) says that on this machine the accounts are just the initials. for u in SG sg solomon grundy s.grundy sgrundy solomon.grundy; do nxc rdp 10.112.170.81 -u $u -p 'UmbracoIsTheBest!'; done RDP 10.112.170.81 3389 WIN-LU09299160F [+] WIN-LU09299160F\SG:UmbracoIsTheBest! (Pwn3d!) RDP 10.112.170.81 3389 WIN-LU09299160F [+] WIN-LU09299160F\sg:UmbracoIsTheBest! (Pwn3d!) it works both uppercase and lowercase because Windows doesn't distinguish case in usernames. the extended variants all fail, so the account is exactly SG. --- ## Phase 5 — The flags hidden in the meta the first flag was in an HTML attribute, so it's worth grepping the source of every page instead of reading them by eye: curl -s 'http://10.112.170.81/archive/we-are-hiring/' | grep -iE 'user|admin|THM|