[어설픈] LOB 14번 bugbear 문제풀이

2019. 4. 4. 11:48System Hacking/[LOB] Hacker School

안녕하세요!

오늘은 LOB 14번 문제인

bugbear 문제풀이를 해보도록 하겠습니다!


소스는 아래와 같습니다!

소스가 좀 길어지긴 했네요!


근데 사실 별거는 없습니다!

주석으로 된 부분(execve구하는 코드)이 길어서 그런거죠


간단하게 보자면 똑같이 버퍼는 40byte입니다

그 뒤에 다양한 포인터들 선언되는데

그건 프로그램이 execve의 정확한 주소 구하는데 사용되는 거구요!


argument 개수 2개 보다 작으면 안되고

컴퓨터가 아래의 주석처럼 코드가 쭉 실행되서

execve 함수의 주소를 execve_addr에 담죠!


그 다음에 저희가 argv[1]에 입력한 45~48번째 값들을

ret 변수에 담습니다!


그리고 execve_addr이랑 ret 변수 값이랑 같으면 통과!

다르면 exit!


그 다음에는 strcpy로 항상 그렇듯

취약점이 터지는 구간이죠!


한마디로 이 문제는 ret 주소를 execve로 고정했습니다!

= 잔 생각말고 execve로 exploit 해라


그러면 execve 함수에 대해서 간략하게

알아봐야겠죠?


구글에 검색해보니 다음과 같이 잘 정리된 표가 있어서

그중에 일부를 발췌해왔습니다!



저도 잘 몰라서 찾아보니

shell을 execve로 실행시키면!

execve( "/bin/sh", ( "/bin/sh", 0 ), 0 )

이런 형태를 갖더라구요!


좀 더 이해하기 쉽게 설명해드리면!

execve 첫 번째 인자엔 

/bin/sh 문자열의 주소를 넣으시면 되구요!

(strings 명령어로 확인가능)


두 번째 인자엔 "/bin/sh", 0 의 주소 값이  순서대로 

들어가 있는 주소 값을 넣으면 되구요!


세 번째 인자엔 0만 있는 메모리 주소 값(NULL)을 

넣으면 됩니다!  


자!! 저도 두 번째 인자에서 

언급한 


"주소 값의 메모리 주소 값"


이놈 때문에 한참동안 헷갈려 했습니다!


1) 이렇게 줘야 하는 이유는 execve 함수에서 

1번째 인자는 그냥 포인터이지만

2번째 인자는 더블 포인터이기 때문입니다!


*path => 그냥 포인터

char *const argv[ ] => 더블 포인터 (argv도 포인터이기 때문)


더블포인터 => 일반 포인터와 다르게 주소 값을 한번 더 줘야한다!


좀 더 자세하게 설명하자면!

일반 포인터의 경우(*path) : 주소 2 ----->  값 참조


더블 포인터의 경우 (char *const argv[ ]) : 주소 1 ----> 주소 2 -----> 값 참조  


뭐 그렇기 때문에 저렇게만 잘 주면 

이 문제는 풀립니다!


문제힌트에서 RTL로 적혀있으니

RTL로 execve 함수 실행하면 되겠죠?


그래서 이제 차례대로 

값을 구해보겠습니다!


위에서 ldd로 라이브러리 의존성을 확인하구요!

 nm 명령어를 통해서

execve 함수 주소 먼저 구해봤습니다! 



그 다음에 gdb로 

프로그램을 까봐서

어디에 유용한 게 있을지

확인해봤습니다!



제가 breakpoint를 main+6에 걸어버린 이유는!

좀 더 뒤에다가 걸면 execve 주소를 알맞게 입력하지 않으면

프로그램이 종료되잖아요!


그래서 저기에 멈추고 스택 맨 끝에서부터

뭐라도 건져올려 볼라고

 확인해보니!!!


제가 복사한 파일의 이름인 big가 보이네요!


파일의 이름이 메모리에 올라간다는건!

심볼릭링크로 이름을 바꿔서 

메모리에 올릴 수 있다는 것!

(=간단하게 말하면... 이름을 바꿀 수 있다) 



 이 위치에 이름이 

위치해 있네요! 

 

이건 x/10s 문자열로 출력 한거고!

x/10x로 출력을 하면!

big 문자열의 주소 값이 나오겠죠!!


0xbffffff7 -> big 문자열 주소 -> big


그리고 "/bin/sh" , 0에서

0도 바로 뒤에 있어야 하는데

아래와 같이

/big바로 뒤에 

모두 빈칸이네요!   


뭐 준비가 다 끝난거 같네요!

/bin/sh의 문자열은 

strings 명령어로 찾아 주고요!




/lib/libc.so.6 주소에서 

/bin/sh 위치를 더하니!


아래와 같이 /bin/sh 주소 값이 나오게 됩니다! 



그리고 마지막으로 확인 차 

검증 들어갑니다!


심볼릭링크로 /bin/sh의 주소 값인

0x40100778의 이름으로 링크를 하나

생성합니다!



그리고 gdb에서 확인해보면!

메모리 맨 끝에서 두 번째 자리에!

0x40100778(=/bin/sh 주소)가

들어간 게 보이시죠?


0x40100778의 /bin/sh 주소 값은

0xbffffff7에 담겨 있구요! (더블포인터용으로)




그럼 바로 원래 파일에다가

심볼릭링크를 걸죠!



저희가 넣을 payload에서

execve 함수 인자에 대한

정리를 해봤습니다!



RTL 할 때 

execve 함수 인자 순으로 입력해주시면 돼요!

(함수 인자 push 될 때 맨 끝 인자부터 push 돼서요)


그래서 아래와 같이 최종 payload을 작성했습니다!


더미 44개 + execve 함수 주소로 리턴 + 더미 값 4개 + (execve 첫 번째 인자) /bin/sh 주소+ (두 번째 인자) 주소의 주소 값 0xbffffff7 + (세 번째 인자) NULL인 0xbffffffb(gdb에서 마지막 주소)


이렇게 주니 바로 

exploit이 완료되고 

비밀번호가 보이네요!


고생하셨습니다!