Giter VIP home page Giter VIP logo

ustc-hackergame / hackergame2020-writeups Goto Github PK

View Code? Open in Web Editor NEW
469.0 25.0 67.0 31.39 MB

Hackergame 2020 的官方与非官方题解

License: Other

Dockerfile 0.06% Python 1.78% Makefile 0.02% C 39.26% C++ 47.77% HTML 0.42% CSS 0.61% JavaScript 8.06% Shell 0.02% Go 0.37% Haskell 0.23% Java 0.13% CMake 0.22% Objective-C 0.12% GLSL 0.01% Sage 0.03% Assembly 0.01% Kotlin 0.61% SCSS 0.26%

hackergame2020-writeups's Issues

关于“室友的加密硬盘”官方题解中提到的非预期解

不知是因为 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 倍左右。

Flag 计算机官方题解中的问题

看一直没修,还是开个 issue 提一下。

官方题解中提到 IDA 识别字符串:

逆向的核心过程就是明白程序干了哪些事情,橙色的操作数代表着地址,我们将鼠标悬停在上面,然后右键把它类型转换一下。
[图片]
IDA 就能识别字符串了。

但在此题上下文甚至提供的截图中,这个做法是有问题的:由于段寄存器指向的内存位置不同,IDA 无法一直正确识别一个数字具体引用的位置;此题中 DS 和 SS 的差值就会导致直接在 IDA 中转换内存引用会产生不正确的结果。(甚至截图里直接引用的是一个“字符串+20h“,显然是不正确的。)

我的题解里描述了至少是本题上下文中的具体原理。

从零开始记账工具人

无脑做法: numpy 把 0~100 分成 10000 份(分割函数参数要写10001),交给cn2an 进行转换,凑成字典,翻转字典,对Excel 第一列进行查找乘个数加和,不在范围内只有一个,手动加上得到结果

自复读的复读机-栈帧解法

看到题目一开始的想法是试着去找 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

2048硬玩通关:

打开题目时游戏不会刷新(重新开始),所以在没玩死时可以一次性打开多个界面,当成存档,如果一个界面游戏玩死了,就打开另一个重新玩,玩到足够高的分数时,再打开多个游戏界面,当存档用。

中间人timing-attack padding oracle exp

我没找到有人写这题非预期解的实现,故按题解中的描述实现了一份(还挺快的):

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

超安全的代理服务器

关于超安全的代理服务器这题,提出获取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},

crc128生成多项式怎么计算得到的?

常见的crc32,crc16的生成多项式都是约定好的,不过这次中间人攻击的那道题里面有一个crc128,针对这种位数较多,且不常见的crc(如crc128,crc256等),他们的生成多项式是如何生成的呢?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.