yoshikingのがんばる日記

あたまよくないけどがんばります

SageMathでpythonの外部ライブラリを使う

SageMathの上で外部ライブラリをインポートできなかった問題の解決法がわかったので、ここに書き留めておこうと思います.

解決法

sage -pip install <package_name>

でインストールできます. 今まで、普通のpythonには入っているのに、なんでsageでインポートできないんだ??と思っていたのですが、sageはまた別にインストールしないといけないみたいです.

動作確認

nullcon のrockspaperscisorsという問題で確認してみます. 公式がgithubで丁寧にDockerfile付きで公開しているので、ローカルから試します.

この問題は特にsageを使う要素がないのですが、最後に無理やり print(factor(12)) をしてみました.

from sage.all import *
from collections import Counter
from Crypto.Util.number import long_to_bytes, bytes_to_long
from ptrlib import *
import re

sbox = [221, 229, 120, 8, 119, 143, 33, 79, 22, 93, 239, 118, 130, 12, 63, 207, 90, 240, 199, 20, 181, 4, 139, 98, 78, 32, 94, 108, 100, 223, 1, 173, 220, 238, 217, 152, 62, 121, 117, 132, 2, 55, 125, 6, 34, 201, 254, 0, 228, 48, 250, 193, 147, 248, 89, 127, 174, 210, 57, 38, 216, 225, 43, 15, 142, 66, 70, 177, 237, 169, 67, 192, 30, 236, 131, 158, 136, 159, 9, 148, 103, 179, 141, 11, 46, 234, 36, 18, 191, 52, 231, 23, 88, 145, 101, 17, 74, 44, 122, 75, 235, 175, 54, 40, 27, 109, 73, 202, 129, 215, 83, 186, 7, 163, 29, 115, 243, 13, 105, 184, 68, 124, 189, 39, 140, 138, 165, 219, 161, 150, 59, 233, 208, 226, 176, 144, 113, 146, 19, 224, 111, 126, 222, 178, 47, 252, 99, 87, 134, 249, 69, 198, 164, 203, 194, 170, 26, 137, 204, 157, 180, 168, 162, 56, 81, 253, 213, 45, 21, 58, 24, 171, 37, 82, 53, 50, 84, 196, 232, 242, 244, 64, 80, 10, 114, 212, 187, 205, 28, 51, 182, 16, 107, 245, 211, 85, 92, 195, 5, 197, 200, 31, 183, 61, 123, 86, 167, 154, 41, 151, 35, 247, 246, 153, 95, 206, 149, 76, 112, 71, 230, 106, 188, 172, 241, 72, 156, 49, 14, 214, 155, 110, 102, 116, 128, 160, 135, 104, 77, 91, 190, 60, 42, 185, 96, 97, 251, 218, 133, 209, 65, 227, 3, 166, 255, 25]
p = [5, 9, 1, 8, 3, 11, 0, 12, 7, 4, 14, 13, 10, 15, 6, 2]
round = 16

def pad(data, size = 16):
    pad_byte = (size - len(data) % size) % size
    data = data + bytearray([pad_byte]) * pad_byte
    return data

def repeated_xor(p, k):
    return bytearray([p[i] ^ k[i % len(k)] for i in range(len(p))])

def inv_hash(rps, data):
    key = pad(rps, 16)
    state = data
    for _ in range(round):
        tmp = bytearray(16)
        for i in range(len(state)):
            tmp[i] = state[p[i]]
        state = tmp
        for i in range(len(state)):
            state[i] = sbox.index(state[i])
        state = repeated_xor(state, key)
    return state

def attack(datas):
    res = ""
    rps = [b'r', b'p', b's']
    # find middle state
    t = []
    for data in datas:
        for i in rps:
            s = inv_hash(i, long_to_bytes(int(data, 16)))
            t.append(hex(bytes_to_long(s)))
    print(Counter(t))
    middle_state = Counter(t).most_common()[0][0]
    print("[+] middle_state:", middle_state)
    # find first hand
    hand = ""
    for i in rps:
        h = hex(bytes_to_long(inv_hash(i, long_to_bytes(int(datas[0], 16)))))
        print(middle_state, h)
        if middle_state == h:
            hand = i
    return hand

def win(hand):
    my = b""
    if hand == b"r":
        my = b"p"
    elif hand == b"s":
        my = b"r"
    elif hand == b"p":
        my = b"s"
    return my


sock = Socket("localhost", 12121)
for i in range(20):
    hoge = sock.recvline()
    if b"You lose!" in hoge:
        print("[+] omg")
        break
    print("[*] i:", i)
    datas = re.compile(r" ([\dabcdef]{5,})").findall(sock.recvline().decode())
    print("[+] datas:", datas)
    hand = attack(datas)
    print(hand)
    w = win(hand)
    print(w)
    sock.recvuntil("Your move:")
    sock.sendline(w)
print(factor(12))
sock.interactive()
2^2 * 3
[ptrlib]$ My move was: s Secret was: ecc880e813f9c8315e30c8d8c672ed41
You win
Your reward is hackim20{b4d_pr1mitiv3_beats_all!1!_7f65}

きちんとできてますね!!!!

ちなみに実際にやられた方はわかると思いますが、初めに DeprecationWarning: invalid escape sequence が出るのですが動くので無視します.

参考

ask.sagemath.org