此bug已提交至官方论坛,bugtrack id 10529,https://bugs.wireshark.org/bugzilla/show_bug.cgi?id=10529。
漏洞作者:blast(http://nul.pw)
事发此崩溃:
(14b4.1dd8): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
*** ERROR: Symbol file could not be found. Defaulted to export symbols for F:\Program Files\Wireshark\Qt5Core.dll -
*** WARNING: Unable to verify checksum for qtshark.exe
*** ERROR: Module load completed but symbols could not be loaded for qtshark.exe
Qt5Core!QPersistentModelIndex::row:
00000000`5f2d5bd0 488b01 mov rax,qword ptr [rcx] ds:baadf00d`baadf00d=????????????????
(注:上面这个崩溃是从调试器启动的,所以堆上未初始化的数据是以baadf00d这个填充模式填入的,实际运行时应该是00000000`00000000,上面是越界8字节的情况)
查看崩溃附近的代码:
0:000> ub .
Qt5Core!QPersistentModelIndex::operator!=+0x58:
00000000`5f2d5bc8 cc int 3
00000000`5f2d5bc9 cc int 3
00000000`5f2d5bca cc int 3
00000000`5f2d5bcb cc int 3
00000000`5f2d5bcc cc int 3
00000000`5f2d5bcd cc int 3
00000000`5f2d5bce cc int 3
00000000`5f2d5bcf cc int 3
0:000> u .
Qt5Core!QPersistentModelIndex::row:
00000000`5f2d5bd0 488b01 mov rax,qword ptr [rcx]
00000000`5f2d5bd3 4885c0 test rax,rax
00000000`5f2d5bd6 7403 je Qt5Core!QPersistentModelIndex::row+0xb (00000000`5f2d5bdb)
00000000`5f2d5bd8 8b00 mov eax,dword ptr [rax]
00000000`5f2d5bda c3 ret
00000000`5f2d5bdb 83c8ff or eax,0FFFFFFFFh
00000000`5f2d5bde c3 ret
00000000`5f2d5bdf cc int 3
崩溃发生在Qt5Core!QPersistentModelIndex::row的第一行,函数试图将第一个参数(rcx)解引用给eax时崩溃。
0:000> .frame /c 1
01 00000000`001da420 00000000`5f8755e6 qtshark+0x90612
rax=baadf00dbaadf00d rbx=00000000001da6e8 rcx=baadf00dbaadf00d
rdx=0000000002c04e00 rsi=0000000000000014 rdi=00000000001da630
rip=000000013f820612 rsp=00000000001da420 rbp=00000000001da589
r8=0000000000008000 r9=0000000000000008 r10=0000000000350268
r11=00000000001d9d88 r12=0000000002d3f300 r13=0000000000000003
r14=0000000002d49d30 r15=0000000002d3f300
iopl=0 nv up ei pl nz na po nc
cs=0033 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010206
qtshark+0x90612:
00000001`3f820612 498b4c2448 mov rcx,qword ptr [r12+48h] ds:00000000`02d3f348=00c4a43f01000000
0:000> dd rcx
baadf00d`baadf00d ???????? ???????? ???????? ????????
baadf00d`baadf01d ???????? ???????? ???????? ????????
baadf00d`baadf02d ???????? ???????? ???????? ????????
baadf00d`baadf03d ???????? ???????? ???????? ????????
baadf00d`baadf04d ???????? ???????? ???????? ????????
baadf00d`baadf05d ???????? ???????? ???????? ????????
baadf00d`baadf06d ???????? ???????? ???????? ????????
baadf00d`baadf07d ???????? ???????? ???????? ????????
看看r12是从哪儿传来的,上方有一个mov rcx,rax,
0:000> uf .
qtshark+0x905e0:
00000001`3f8205e0 4053 push rbx
00000001`3f8205e2 4154 push r12
00000001`3f8205e4 4883ec48 sub rsp,48h
00000001`3f8205e8 488bda mov rbx,rdx
00000001`3f8205eb 4c8be1 mov r12,rcx ;here
00000001`3f8205ee ff15c4b21100 call qword ptr [qtshark+0x1ab8b8 (00000001`3f93b8b8)]
00000001`3f8205f4 49837c244800 cmp qword ptr [r12+48h],0
00000001`3f8205fa 0f84a1010000 je qtshark+0x907a1 (00000001`3f8207a1)
qtshark+0x90600:
00000001`3f820600 488bcb mov rcx,rbx
00000001`3f820603 ff158f931100 call qword ptr [qtshark+0x1a9998 (00000001`3f939998)]
00000001`3f820609 488bc8 mov rcx,rax
00000001`3f82060c ff158e931100 call qword ptr [qtshark+0x1a99a0 (00000001`3f9399a0)]
为了验证,在函数开头下断点,重新启动程序:
0:000> g
Breakpoint 0 hit
qtshark+0x905e0:
00000001`3f3d05e0 4053 push rbx
0:000> r
rax=000000013f515d48 rbx=0000000002aff6c0 rcx=0000000002aff6c0
rdx=000000000023a488 rsi=0000000000000014 rdi=000000000023a3d0
rip=000000013f3d05e0 rsp=000000000023a218 rbp=000000000023a329
r8=000000000023a490 r9=000000000023a3d0 r10=000000005fb1a340
r11=000000005fa55228 r12=000000000023a3d0 r13=0000000000000003
r14=0000000002b09fe0 r15=0000000002aff6c0
iopl=0 nv up ei pl nz na po nc
cs=0033 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000206
qtshark+0x905e0:
00000001`3f3d05e0 4053 push rbx
执行期间可以发现:
0:000>
qtshark+0x90603:
*** ERROR: Symbol file could not be found. Defaulted to export symbols for F:\Program Files\Wireshark\Qt5Core.dll -
00000001`3f3d0603 ff158f931100 call qword ptr [qtshark+0x1a9998 (00000001`3f4e9998)] ds:00000001`3f4e9998={Qt5Core!QList<QItemSelectionRange>::front (00000000`5f962d00)}
0:000>
qtshark+0x90609:
00000001`3f3d0609 488bc8 mov rcx,rax
0:000> r rax
Last set context:
rax=baadf00dbaadf00d
看来是Qt5Core!QList::front 的问题,重启bp qtshark+0x90603。
让我们看一下正常的操作是什么:
Breakpoint 0 hit
qtshark+0x90603:
00000001`3f9e0603 ff158f931100 call qword ptr [qtshark+0x1a9998 (00000001`3faf9998)] ds:00000001`3faf9998={Qt5Core!QList<QItemSelectionRange>::front (00000000`5f462d00)}
0:000> r
rax=0000000000000000 rbx=000000000030a0d8 rcx=000000000030a0d8
rdx=0000000000000000 rsi=0000000000000014 rdi=000000000030a048
rip=000000013f9e0603 rsp=0000000000309e20 rbp=0000000000309f89
r8=0000000000008000 r9=0000000000000008 r10=00000000003e0268
r11=0000000000309788 r12=0000000002c2f440 r13=0000000000000003
r14=0000000002c39e20 r15=0000000002c2f440
iopl=0 nv up ei pl nz na po nc
cs=0033 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000206
qtshark+0x90603:
00000001`3f9e0603 ff158f931100 call qword ptr [qtshark+0x1a9998 (00000001`3faf9998)] ds:00000001`3faf9998={Qt5Core!QList<QItemSelectionRange>::front (00000000`5f462d00)}
进入之后,
0:000> t
Qt5Core!QList<QItemSelectionRange>::front:
00000000`5f462d00 488b11 mov rdx,qword ptr [rcx] ds:00000000`0030a0d8=80c6310500000000
0:000>
Qt5Core!QList<QItemSelectionRange>::front+0x3:
00000000`5f462d03 48634208 movsxd rax,dword ptr [rdx+8] ds:00000000`0531c688=00000000
0:000> t
Qt5Core!QList<QItemSelectionRange>::front+0x7:
00000000`5f462d07 488b44c210 mov rax,qword ptr [rdx+rax*8+10h] ds:00000000`0531c690=f0c52d0500000000
0:000> r
rax=0000000000000000 rbx=000000000030a0d8 rcx=000000000030a0d8
rdx=000000000531c680 rsi=0000000000000014 rdi=000000000030a048
rip=000000005f462d07 rsp=0000000000309e18 rbp=0000000000309f89
r8=0000000000008000 r9=0000000000000008 r10=00000000003e0268
r11=0000000000309788 r12=0000000002c2f440 r13=0000000000000003
r14=0000000002c39e20 r15=0000000002c2f440
iopl=0 nv up ei pl nz na po nc
cs=0033 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000206
Qt5Core!QList<QItemSelectionRange>::front+0x7:
00000000`5f462d07 488b44c210 mov rax,qword ptr [rdx+rax*8+10h] ds:00000000`0531c690=f0c52d0500000000
0:000> t
Qt5Core!QList<QItemSelectionRange>::front+0xc:
00000000`5f462d0c c3 ret
0:000> r
rax=00000000052dc5f0
这一次执行结果是返回了一个指针。
这是不正常的走向:
0:000> r
rax=0000000000000000 rbx=00000000001da648 rcx=00000000001da648
rdx=000007feebae9ff0 rsi=0000000000000014 rdi=00000000001da590
rip=000000013f860603 rsp=00000000001da380 rbp=00000000001da4e9
r8=0000000000000005 r9=0000000000000069 r10=0000000000000000
r11=0000000000000002 r12=00000000027bf3f0 r13=0000000000000003
r14=00000000027c9e30 r15=00000000027bf3f0
iopl=0 nv up ei pl nz na po nc
cs=0033 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000206
qtshark+0x90603:
00000001`3f860603 ff158f931100 call qword ptr [qtshark+0x1a9998 (00000001`3f979998)] ds:00000001`3f979998={Qt5Core!QList<QItemSelectionRange>::front (00000000`5f962d00)}
0:000> t
Qt5Core!QList<QItemSelectionRange>::front:
00000000`5f962d00 488b11 mov rdx,qword ptr [rcx] ds:00000000`001da648=10cf6b0200000000
0:000>
Qt5Core!QList<QItemSelectionRange>::front+0x3:
00000000`5f962d03 48634208 movsxd rax,dword ptr [rdx+8] ds:00000000`026bcf18=01000000
0:000>
Qt5Core!QList<QItemSelectionRange>::front+0x7:
00000000`5f962d07 488b44c210 mov rax,qword ptr [rdx+rax*8+10h] ds:00000000`026bcf28=0df0adba0df0adba
0:000>
Qt5Core!QList<QItemSelectionRange>::front+0xc:
00000000`5f962d0c c3 ret
由于每次操作会产生2个selection change事件,所以有问题的是第二个操作。
Qt5Core!QList<QItemSelectionRange>::front:
mov rdx,qword ptr [rcx]
movsxd rax,dword ptr [rdx+8]
mov rax,qword ptr [rdx+rax*8+10h]
ret
而这个函数的整个操作就这4行。
rdx = *rcx;
rax = *(rdx+8);
return *(rdx+rax*8+0x10);
综合一下就是:
return *(*rcx+(*(rdx+8))*8+0x10);
实际执行起来是:
return *(*arg1+0x10);
或者
return *(*arg1+0x18);
//取决于选的数量
由于我们没有符号,不知道具体代表什么,但是再出问题的部分,如果执行:
0:000> r
rax=0000000000000001 rbx=000000000015a6c8 rcx=000000000015a6c8
rdx=0000000005143d90 rsi=0000000000000014 rdi=000000000015a610
rip=000000005f462d07 rsp=000000000015a3f8 rbp=000000000015a569
r8=0000000000008000 r9=0000000000000008 r10=0000000001f30268
r11=0000000000159d68 r12=0000000002d3f220 r13=0000000000000003
r14=0000000002d49bb0 r15=0000000002d3f220
iopl=0 nv up ei pl nz na po nc
cs=0033 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000206
Qt5Core!QList<QItemSelectionRange>::front+0x7:
00000000`5f462d07 488b44c210 mov rax,qword ptr [rdx+rax*8+10h] ds:00000000`05143da8=0df0adba0df0adba
0:000> dd rdx+10
00000000`05143da0 02d678b0 00000000 baadf00d baadf00d
00000000`05143db0 abababab abababab abababab abababab
看到好玩的了吧,这纯粹是越界访问了。那么既然选一个就是+0x8,如果可以选上更多的数据,是否就可以读到后面的0x00000040 00000000呢?我猜应该是可以的吧=v=
0:000> .cxr
Resetting default scope
0:000> dd rdx+10
00000000`05143da0 02d678b0 00000000 baadf00d baadf00d
00000000`05143db0 abababab abababab abababab abababab
00000000`05143dc0 00000000 00000000 00000000 00000000
00000000`05143dd0 00000040 00000000