HackThisSite - Application Mission 16

Challenge

Application Challenge 16 (medium)

官方只给了难度等级,没有标题和描述:目标是找出程序要求输入的 password,然后到 challenge 页面提交。

程序包里只有一个 Windows 控制台 exe:app16win.zipapp16win.exe

Solution

  • file 显示 PE32 executable for MS Windows 4.00 (console), Intel i386, 8 sections
  • strings 搜不到任何明文校验逻辑:grep -i freedomgrep -i speech 都是 0 命中,但命中了一条打包器横幅(Quick Batch File Compiler)。
  • 这说明 exe 是把批处理脚本编译出来的壳:程序运行时才把真正的 .bat 释放到 %TEMP%,再交给 cmd.exe 解释执行。真正的密码校验在释放出来的批处理里,所以静态搜索字符串无法命中。
1
2
3
4
5
6
7
8
9
10
$ file app16win.exe
app16win.exe: PE32 executable for MS Windows 4.00 (console), Intel i386, 8 sections

$ strings -n 6 app16win.exe | grep -i -m3 -E 'batch|compiler'
Quick Batch File Compiler

$ strings -n 4 app16win.exe | grep -i -c freedom
0
$ strings -n 4 app16win.exe | grep -i -c speech
0

密码被编译进了释放时才解压出来的批处理。

程序是 set /p + pause 的交互式脚本,直接跑会停在等待输入;同时它释放的临时 .bat 会在退出时被清理。用 FIFO 顶住输入、抢时间把临时文件复制出 Wine 前缀:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#!/usr/bin/env bash
# Run app16, grab the QBFC-extracted .bat, copy it OUT of the prefix, kill app.
set -u
cd <hts-workspace>/challenges/hts-app/app16
rm -f /tmp/app16fifo; mkfifo /tmp/app16fifo
( sleep 20 > /tmp/app16fifo ) &
HOLDER=$!
timeout 20 wine app16win.exe < /tmp/app16fifo > /tmp/app16_out.txt 2>/dev/null &
WPID=$!
sleep 5
BAT=$(find ~/.wine -type f -iname "*.bat" -newermt "-30 seconds" 2>/dev/null | head -1)
echo "found: $BAT"
if [ -n "$BAT" ]; then
cp "$BAT" ./extracted.bat
ls -la ./extracted.bat
fi
sleep 1
# copy again by inode snapshot in case of rename
find ~/.wine -type f -iname "*.bat" 2>/dev/null -exec cp {} ./extracted_2.bat \;
wait $WPID 2>/dev/null
kill $HOLDER 2>/dev/null
echo "done"
1
2
3
4
$ bash capture_bat.sh
found: ~/.wine/drive_c/users/<user>/AppData/Local/Temp/bt2136.bat
-rw-r--r-- 1 <user> <user> 199 Sep 11 15:44 ./extracted.bat
done

释放路径在 Wine 里对应宿主机的 ~/.wine/drive_c/users/<user>/AppData/Local/Temp/,文件名是 bt<随机数>.bat

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ cat -A extracted.bat
@shift 1^M$
@echo off^M$
echo Enter Password:^M$
set pass=^M$
set /p pass=^M$
if "%pass%"=="speech" goto pass2^M$
Echo wrong password!^M$
pause^M$
exit^M$
:pass2^M$
Echo Congrats! HTS password is freedom.^M$
pause^M$
exit^M$

逻辑一目了然:输入字符串和 speech 比较,相等就跳到 :pass2 并打印明文答案。.bat 里的回显会把答案原样念出来,所以只要拿到释放出来的脚本,既知道输入口令也知道 HTS 要提交的密码。

把口令喂给原程序,确认它自己打印出密码:

1
2
3
4
5
6
7
8
9
$ printf 'speech\n\n' | timeout 40 wine app16win.exe 2>/dev/null | tr -d '\r'
Enter Password:
Congrats! HTS password is freedom.
Press any key to continue...

$ printf 'wrong\n\n' | timeout 40 wine app16win.exe 2>/dev/null | tr -d '\r'
Enter Password:
wrong password!
Press any key to continue...

程序自身的输出即为验证依据,无需提交到 HTS 也能确认答案正确。

Vulnerabilities

编译成 exe 只是打包,不是保护。批处理校验逻辑会以明文形式释放到用户可写的临时目录,任何能在同一台机器上观察进程/临时目录的人都可直接读取口令,并且程序自身会在成功路径上回显答案。修复方向:不要把秘密放在客户端可执行的脚本里;如果必须做本地校验,使用真正的编译语言并把校验值与用户输入做不可逆校验(而不是可回读的明文比较),同时避免在成功路径输出敏感信息。

freedom