ustc-hackergame / hackergame2020-writeups Goto Github PK
View Code? Open in Web Editor NEWHackergame 2020 的官方与非官方题解
License: Other
Hackergame 2020 的官方与非官方题解
License: Other
打开static/js/game_manager.js,看到第170行,修改成“if (true) self.won = true;”,保存,然后随便走几步,ok
看到题目一开始的想法是试着去找 input
读入变量的值。
但是把源码拖下来一看,exec(input())
,这没法玩啊。
这行代码的字节码:
1 0 LOAD_NAME 0 (exec)
2 LOAD_NAME 1 (input)
4 CALL_FUNCTION 0
6 CALL_FUNCTION 1
8 RETURN_VALUE
Python 内部完全没提供访问这个 input 输入临时字符串的功能。
str 类型不受 gc 跟踪,代表 gc.get_objects()
没法用,又因为这是个中间变量,也不存在于 globals,locals 里,代码对象也和这玩意没关系。
本来想着试试 ctypes 到处摸一摸,但在写的时候发现在 exec 中有更方便的解法。
exec 本身就是一个确定的代码对象,可以从栈帧上找到这个代码对象和它的常量等信息,稍微好做一点。
inner_code = b'''import inspect
import hashlib
d=inspect.currentframe().f_back.f_code.co_consts[0]
inp=f"exec(bytes.fromhex('{d}').decode())"
print(hashlib.sha256(inp.encode()).hexdigest(),end='')
'''.hex()
print(f'exec(bytes.fromhex(\'{inner_code}\').decode())')
(从大佬那学到了从mem里翻出输入字符串 大佬tql
由于域名检查的逻辑十分简单,因此我创建了一条 ustc.edu.cn.example.com
指向 127.0.0.1
的 DNS 记录,以此绕过ACL。
瞎折腾了……
无脑做法: numpy 把 0~100 分成 10000 份(分割函数参数要写10001),交给cn2an 进行转换,凑成字典,翻转字典,对Excel 第一列进行查找乘个数加和,不在范围内只有一个,手动加上得到结果
苏卡卡明明是因为无聊,直接从 META 里找到了原始 Repository。
META 里的 Hash、Star、Watcher 数、Repo Size 都不改的,当然找到了 openlug/nonexist
的原始仓库。
我没找到有人写这题非预期解的实现,故按题解中的描述实现了一份(还挺快的):
from pwn import *
from hashlib import sha256
from utils import *
import time
is_remote = True if 1 == 1 else False # chang this for switch remote/local
if is_remote:
r = remote('202.38.93.111', 10041)
r.sendlineafter('token:', 'xxx:yyy') # your token
else:
r = process(['python3', './entry.py'])
r.sendlineafter('to play (1/2/3)? ', '3') # chang this for switch task2/3
def enc(prefix, suffix):
r.sendlineafter('talk to? ', 'Alice')
r.sendlineafter('s your name? ', bytes(prefix).hex())
r.sendlineafter(' else do you want to say? ', bytes(suffix).hex())
c = r.recvuntil('Whom do')
return bytes.fromhex(c.split(b'please take it to Bob:\n')[1].split(b'\nWhom do')[0].decode())
prelen = len(b"Thanks " + b" for taking my flag: ")
def calc_len():
global prelen
st = len(enc(b'',b''))
app = 0
while True:
app += 1
if len(enc(b'a' * app,b'')) != st:
break
return st - app - prelen - 16 - len(hmac_crc128(b'x' * 16,b'y' * 16))
def oracle_test(data):
r.sendlineafter('talk to? ', 'Bob')
r.sendlineafter('essage from Alice: ', bytes(data).hex())
t = time.time()
c = r.recvuntil('Whom do')
t = time.time() - t
return t
def original_oracle(data):
r.sendlineafter('talk to? ', 'Bob')
r.sendlineafter('essage from Alice: ', bytes(data).hex())
t = time.time()
c = r.recvuntil('Whom do')
t = time.time() - t
if t < theta:
return False
return True
test_cnt = 5
def oracle(data):
global test_cnt
t_cnt = 0; f_cnt = 0
for i in range(test_cnt):
if original_oracle(data):
t_cnt += 1
else:
f_cnt += 1
if (t_cnt == 0 and f_cnt >= 2) or (f_cnt == 0 and t_cnt >= 2):
break
if t_cnt > test_cnt // 2 or f_cnt > test_cnt // 2:
break
return True if t_cnt > f_cnt else False
alphabet = b'qwertyuiopasdfghjklzxcvbnm' # more possible char in flag (for speed up)
morePoss = b'0123456789_' + alphabet + alphabet.upper() + b'{}\n'
def padding_attack(chiper, required, known = b''):
for i in range(len(chiper), len(chiper) - required, -1):
if i + len(known) > len(chiper):
continue
cons = (len(chiper) - i) % 16
val = cons + 1
cur = None
in_chiper = chiper[i - 17]
pre = chiper[: i - 17]
suffix = bytes([known[j] ^ chiper[i - 16 + j] ^ val for j in range(cons)])
suffix += chiper[i - 16 + cons : len(chiper) - (len(chiper) - i) // 16 * 16]
poss = []
for j in morePoss:
poss.append(j ^ val ^ in_chiper)
for j in range(256):
if j not in poss:
poss.append(j)
for j in poss:
if oracle(pre + bytes([j]) + suffix):
cur = j ^ val ^ in_chiper
if val == 1:
if j != in_chiper:
break
else:
break
if cur == None:
print('failed')
quit()
else:
known = bytes([cur]) + known
#if len(chiper) == i:
# known = known * known[0] # is padding
print(known)
flag_len = calc_len()
rubbish_len = 3000 # change this when the network is slow
rubbish_len = rubbish_len + 16 - (rubbish_len + prelen + flag_len) % 16
wanted_cnt = flag_len
known = b''
good = enc(b'*'*rubbish_len, b'')
t1 = oracle_test(good)
bad = good[:-1] + bytes([good[-1] ^ 1])
t2 = oracle_test(bad)
goods = enc(b'*'*(rubbish_len - wanted_cnt), b'')
t1s = oracle_test(goods)
bads = goods[:-1] + bytes([goods[-1] ^ 1])
t2s = oracle_test(bads)
print('good time = ', t1s, '~', t1)
print('bad time = ', t2s, '~', t2)
if t1s < t2:
print('waring: bad oracle!')
theta = (t1s + t2) / 2
print('suggest theta = ', theta)
padding_attack(enc(b'*'*rubbish_len, b'')[:-32], wanted_cnt, known)
可以先把滑标拖到0,点击提交后上方的网址会出现balabal/number=0,将其改为number=1,就可以得到flag
qwq
看一直没修,还是开个 issue 提一下。
官方题解中提到 IDA 识别字符串:
逆向的核心过程就是明白程序干了哪些事情,橙色的操作数代表着地址,我们将鼠标悬停在上面,然后右键把它类型转换一下。
[图片]
IDA 就能识别字符串了。
但在此题上下文甚至提供的截图中,这个做法是有问题的:由于段寄存器指向的内存位置不同,IDA 无法一直正确识别一个数字具体引用的位置;此题中 DS 和 SS 的差值就会导致直接在 IDA 中转换内存引用会产生不正确的结果。(甚至截图里直接引用的是一个“字符串+20h“,显然是不正确的。)
我的题解里描述了至少是本题上下文中的具体原理。
关于超安全的代理服务器
这题,提出获取Secret的Method3
可以用chrome://net-internals/#http2
新版的chrome把此功能改到了chrome://net-export/
,通过log文件读到
{"params":{"headers":[":method: GET",":scheme: https",":authority: 146.56.228.227",":path: /62d9b249-d6d8-4714-8ea0-9f3b413d5165"],"id":85,"promised_stream_id":54},"phase":0,"source":{"id":76608,"start_time":"319510568","type":9},"time":"320091658","type":206},
不知是因为 LUKS 分区打开的时候本该如此,还是出题人操作不慎在分区创建的时候密码复制到了剪贴板上,密码本身明文在 swap 中出现了,所以 strings 一下然后逐个字符串尝试就可以求解。但感觉其实这样做出来也算是正常解法了。密码是什么留作练习。
一时兴起想试着通过这种方式解一下,首先将 swap 分区单独拿出来:
dd if=roommates_disk_part.img of=swap.img bs=512 count=1497088 skip=393216
然后用 GCC binutils 中的 strings
工具将文件中的字符串提取出来:
strings swap.img > swap.strings
一眼看过去挺多重复的,用 uniq
去一下重:
sort swap.strings | uniq > swap.strings.uniq
这样就得到了一个词典,使用 Hashcat 的 LUKS 模式破解:
hashcat -a 0 -m 14600 chome.img swap.strings.uniq -o hashcat-recovered2 --force
在旧机子上跑了一整天,破解出来了一个密码(Recovered...1/2,因为事先按照官方题解添加了一个密码 1
所以显示有两个)
[s]tatus [p]ause [b]ypass [c]heckpoint [q]uit => s
Session..........: hashcat
Status...........: Running
Hash.Name........: LUKS
Hash.Target......: chome.img
Time.Started.....: Mon Feb 1 16:43:05 2021, (1 day, 2 hours)
Time.Estimated...: Wed Feb 3 07:46:31 2021, (12 hours, 27 mins)
Guess.Base.......: File (swap.strings.uniq)
Guess.Queue......: 1/1 (100.00%)
Speed.#1.........: 11 H/s (6.58ms) @ Accel:4 Loops:128 Thr:8 Vec:1
Recovered........: 1/2 (50.00%) Digests, 1/2 (50.00%) Salts
Progress.........: 1140480/2129440 (53.56%)
Rejected.........: 0/1140480 (0.00%)
Restore.Point....: 569856/1064720 (53.52%)
Restore.Sub.#1...: Salt:1 Amplifier:0-1 Iteration:503296-503424
Candidates.#1....: K-|g.} -> ki
$ cat hashcat-recovered
chome.img:h189-~asfnb.asdfjp2i3
看起来 h189-~asfnb.asdfjp2i3
就是密码了,试着用这个密码解密分区,成功。
$ dd if=roommates_disk_part.img of=chome.img bs=512 count=1998848 skip=1892352
$ sudo cryptsetup luksOpen chome.img chome
Enter passphrase for chome.img: h189-~asfnb.asdfjp2i3
$ sudo mount /dev/mapper/chome /mnt
$ cat /mnt/petergu/flag.txt
flag{lets_do_A_c01d_b00t_next_time}
一些细节:虽然我的机子是 i915 集成显卡,但用使用了 GPU 计算的 Hashcat 仍然比使用多线程 CPU 运算的 bruceforce-luks 要快 20 倍左右。
昨天搜 oblivious transfer crack 搜到的 2333
https://crypto.stackexchange.com/questions/85973/1-2-oblivious-transfer-can-the-recepient-obtain-both-secrets-by-manipulating-v
打开题目时游戏不会刷新(重新开始),所以在没玩死时可以一次性打开多个界面,当成存档,如果一个界面游戏玩死了,就打开另一个重新玩,玩到足够高的分数时,再打开多个游戏界面,当存档用。
常见的crc32,crc16的生成多项式都是约定好的,不过这次中间人攻击的那道题里面有一个crc128,针对这种位数较多,且不常见的crc(如crc128,crc256等),他们的生成多项式是如何生成的呢?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.