这次SUCTF中,我出了一道PHP OPCODE逆向的Web,应该算是国内最早出PHP OPCODE逆向的人了,稍微写一下一点思考。

思路来源

这个思路是去年想到的,当时在看PHP内核方面的资料,但是一开始并没有想到这里,而是去朝着底层识别webshell的,后面在继续了解到了PHP的OPCODE之后,发现PHP的OPCODE可读性非常高,不论是对于函数的标明还是逻辑的走向,都十分的清晰,唯一的难点便是对于各种指令和PHP底层处理机制的不熟悉,在我的预计中,这一块稍微弄清楚的话,大概几个小时便可以做到。

在查看了国内以及国外这方面的资料都不是很多的情况下,就萌生了出一道这方面CTF的想法,于是在寒假的时候,基本泡在了这里面,构思好了大致的题目脉络:

Git Tag还原代码 + OPCODE逆向 + PHP so扩展解密 + CFB重放攻击 + 正则绕过

具体实现

其实这一块的东西并不算多,因为PHP已经有vld扩展了,可以直接将文件的OPCODE拿到,因此剩下的工作也就不多了,只需要写好文件,然后vld加载一下。

这里还有个有趣的问题是关于PHP中include函数的,在这之前,我一直以为include是类似于动态加载代码的,然而在看到OPCODE之后,我发现事情可能没有这么简单,因为我看到了index.php中include的function的OPCODE,因此我觉得可能是加载OPCODE,但是这方面我也并未深究过,因此不敢说事实就是如此。

函数OPCODE的构成

这里稍微涉及一下PHP中OPCODE对于函数的处理,这也是我觉得PHP的OPCODE可读性高的原因之一:

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
filename:       /Applications/MAMP/htdocs/CTF/SUCTF/SUCTF/func.php
function name: viewImage
number of ops: 19
compiled vars: !0 = $name
line #* E I O op fetch ext return operands
-------------------------------------------------------------------------------------
78 0 E > EXT_NOP
1 RECV !0
79 2 EXT_STMT
3 FETCH_R global $0 '_SESSION'
4 FETCH_DIM_R $1 $0, 'auth'
5 IS_NOT_IDENTICAL ~2 $1, 'admin'
6 > JMPZ ~2, ->10
80 7 > EXT_STMT
8 > EXIT 'Auth+Failed'
81 9* JMP ->10
82 10 > EXT_STMT
11 FETCH_CLASS 0 :3 'ImageView'
12 EXT_FCALL_BEGIN
13 NEW :3
14 SEND_VAR !0
15 DO_FCALL_BY_NAME 1
16 EXT_FCALL_END
83 17 EXT_STMT
18 > RETURN null

branch: # 0; line: 78- 79; sop: 0; eop: 6; out1: 7; out2: 10
branch: # 7; line: 80- 80; sop: 7; eop: 8; out1: -2
branch: # 10; line: 82- 83; sop: 10; eop: 18; out1: -2
path #1: 0, 7,
path #2: 0, 10,
End of function viewimage

源代码如下:

1
2
3
4
5
6
7

function viewImage($name){
if($_SESSION['auth'] !== "admin"){
die("Auth Failed");
}
new ImageView($name);
}

可以看到,OPCODE中清楚的标明了文件位置、函数名称、OPCODE数量等信息。

再仔细看OPCODE,你能发现,操作指令的可读性也非常高,比如EXT_FCALL_BEGIN、DO_FCALL_BY_NAME等。

并且OPCODE与正常代码的顺序也几乎一样。

一点吐槽

我知道我出这样的题目,除了有师傅会觉得喜欢以外,肯定会有人吐槽:

这样的题目有什么用,我日战用的到吗

为什么要考这些偏门冷门的东西,没有意义

逻辑部分那么长,你还要我们逆,是不是太无聊了

其实,这一部分也是我一直以来对CTF的看法,CTF从来不是实战,自然也就不应该拿实战的眼光来看它,一个好的CTF题目至少应该在某些方面具有新颖性、能让人打开知识广度、加深知识的深度,以及某些极个别情况下的攻击手法。你问为什么不贴合实战?要实战自己日战去。

过于纠结CTF与实战脱节我觉得是没有意义的,那么多众测活动不做,来跟一个CTF较劲不是很没趣?CTF自然是应该去挖掘更精巧,更前沿的攻击方式。

当然,我并不是说CTF就应该脑洞,CTF应该给予选手适当的引导,在选手经过构思以及学习之后,能找到攻击的思路,这才是比较合理的。

以上