Challenge
Level 11 — Reverse Ascii Shift
页面给出一串随机生成的
%分隔的 ASCII 码和一个 Shift 值。把每个码按 Shift 反向还原,得到的字符串就是答案(Decoded ASCII)。限时 3 秒。This string was randomly generated. It will not be recognizable text. You have 3 seconds to take the information from the website, and apply that to your algorithm.
Solution
- 实例页
https://www.hackthissite.org/missions/prog/11/的正文里有三行:Generated String: 89%71%64%55%42%89%84%37%57%、Shift: 3、Decoded ASCII。 - 表单只有一个
solution字段,submit (remaining time: 3 seconds)
Level 11This string was randomly generated. It will not be recognizable text. You have 3 seconds to take theinformation from the website, and apply that to your algorithm.Generated String: 89%71%64%55%42%89%84%37%57%Shift: 3 Decoded ASCII% 只是分隔符,每个数字是一个被平移过的字符码。题面用词是 reverse(反向还原),所以先尝试 chr(code - shift);实测该方向被服务端直接接受:
#!/usr/bin/env python3"""Solve HackThisSite Programming Mission 11."""
import htmlimport osimport re
import requests
BASE = "https://www.hackthissite.org"LEVEL_URL = f"{BASE}/missions/prog/11/"USER_AGENT = ( "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 " "(KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36")
def make_session(): cookie = os.environ.get("HTS_COOKIE", "").strip().strip("'\"") if not cookie:95 collapsed lines
raise SystemExit("HTS_COOKIE is not set") client = requests.Session() client.headers.update( { "User-Agent": USER_AGENT, "Cookie": cookie, "Referer": f"{BASE}/missions/programming/", "Accept-Language": "en-US,en;q=0.9", } ) return client
def body_text(source): source = re.sub(r"<script.*?</script>", "", source, flags=re.S) source = re.sub(r"<br\s*/?>", "\n", source) source = re.sub(r"</(?:p|div|tr)>", "\n", source) source = re.sub(r"<[^>]+>", " ", source) source = html.unescape(source) return re.sub(r"\n\s*\n+", "\n", re.sub(r"[ \t]+", " ", source))
def parse(page_text): section = page_text.split("Generated String:", 1)[1].split("Shift:", 1)[0] codes = [int(value) for value in re.findall(r"\d+", section)] match = re.search(r"Shift:\s*(\d+)", page_text) if match is None: raise SystemExit("shift value not found") return codes, int(match.group(1))
def decode(codes, shift, direction): return "".join(chr(code + direction * shift) for code in codes)
def verdict(response_text): text = body_text(response_text).lower() success = any( marker in text for marker in ( "congratulation", "you have completed", "completed this", "successfully", "correct", "well done", "mission accomplished", "complete!", ) ) failure = any( marker in text for marker in ( "wrong", "incorrect", "not correct", "try again", "failed", "too late", "time is up", "sorry", ) ) if success and not failure: return True if failure and not success: return False return None
def submit(client, answer): response = client.post( f"{LEVEL_URL}index.php", data={"solution": answer, "submitbutton": "submit"}, headers={"Referer": LEVEL_URL}, timeout=30, ) response.raise_for_status() return verdict(response.text), response.text
def main(): client = make_session() page = client.get(LEVEL_URL, timeout=20) page.raise_for_status() codes, shift = parse(body_text(page.text)) for direction in (-1, 1): answer = decode(codes, shift, direction) print(f"try shift {direction * shift:+d} -> {answer!r}") ok, _ = submit(client, answer) print("verdict:", ok) if ok: return if direction == -1: page = client.get(LEVEL_URL, timeout=20) page.raise_for_status() codes, shift = parse(body_text(page.text)) print("retry codes:", codes, "shift", shift) raise SystemExit("both directions rejected")
if __name__ == "__main__": main()