문제

main에서 실행하고 function함수를 실행한다. buffer1은 15바이트, buffer2는 10바이트

▶ 소스파일 추가

vi test_gdb.c


 컴파일

gcc -o test test_gdb.c

위와 같은 방법으로 컴파일을 하려고 했으나 몇몇 학우들의 과정을 봤는데 32비트로 컴파일을 해주었다.... (왜 32비트로 컴파일 해야되는지는 물어봐야겠다..)

64비트 우분투에서 32비트용 컴파일을 할때 뒤에 -m32을 써준다.

gcc test_gdb test_gdb.c -m32

쓰려니까 에러가 났다.

리눅스 버전 확인

 

getconf LONG_BIT
arch

arch를 입력했을때 출력값이 x86_64면 64bit , i386 또는 i686이 나오면 32bit이다.

 

64bit에서 개발한 프로그램을 32bit에서 호환 가능하도록 패키지를 설치한다.

 

64비트 환경에서 32비트로 컴파일

 

sudo apt-get install gcc-multilib

위에 명령어를 입력해주니 설치가 진행됐고 다시 컴파일을 32비트로 입력했을때 성공했다.

 

gdb로 들어오기

main 함수 보기 위해 disas main을 입력해주었다.

main 함수 부분의 어셈블리 코드들이 보인다.

전역변수에 저장하는 데이터 세그먼트는 없는 상태이다.

eip는 앞으로의 수행할 시작점의 위치를 갖고 있다. main함수의 시작점이다.

eip가 갖고 있는 값은 main함수의 첫번째 0x08048460이다.

 

함수의 프롤로그 부분에 push ebp(base pointer) esp의 값을 4byte 뺀값을 ebp에 넣겠다는 값이다.

mov로 esp를 ebp로 복사하면 둘이 같은 지점을 가리킨다.

sub로 esp에서 4byte를 2번 빼서 8byte만큼 공간을 확장시켰다.

 

인자값을 주기 위해 공간을 확장한것이다. push로 3-2-1순으로 들어간다.

스택구조는 가장 나중에 들어간걸 가장 먼저 꺼내는 FIFO로 1-2-3이 아닌 3-2-1순으로 넣었다.

 

call로 인자값을 담은 것을 function에 넘긴다. 주소는 804383b이다.

잠깐 function함수로 빠져서 function함수를 실행하고 다시 돌아온다.

이때, 다시 어디로 돌아올지 eip에 함수의 시작부분인 0x0804843b이 들어있다.

 

처음 시작점이 어디인지 확인해보기 위한 과정

b * 0x08048460

맨 처음 시작하는거에 브레이크를 걸었다.

맨처음에 걸려있음

그다음에, 

info reg eip

main함수에 맨첫번째 주소가 나오는것을 확인 할 수 있다.

 

 

call 전에 브레이크를 걸고, ls로 쭉 내려가서, 

sub로 28byte만큼 확장하고 있는 것을 볼수 있다.

buffer1이 15byte, buffer2가 10byte인데 , 여기서는 4byte 단위로 할당이 돼서 15byte는 4*4인 16byte가 할당되고 10byte는 4*3=12byte가 할당된다.

따라서 총 28byte가 할당이 된걸 확인할 수 있다.

 

function함수의 시작주소가 eip에 들어있는것을 확인 할 수 있다.

 

다시 function함수에 와서

초록색 부분은 오류 났는지 안났는지 확인한다.

leave ret을 에피로그다.

leave는 mov %ebp, %esp 와 pop %ebp가 묶여 있는 것이다.

 

si로 쭉 내려와서 function을 나가고

더한다는 것은 반환한다는 의미이다. function값도 반환하고 할당하기 이전으로 돌아갔다는 것이 add이다..

 

main에도 프롤로그, 에피로그 과정 있다.

main함수작업을 프롤로그이전으로 돌아가게 된다.

 

 

gdb가 어떻게 돌아가는 건지 과정을 살펴보았다.

GDB설치 과정

 

gdb 설치

sudo apt-get install gdb

 

 

 

peda 설치

git clone https://github.com/longld/peda.git ~/peda

 

echo "source ~/peda/peda.py" >> ~/.gdbinit

 


GDB 명령어

⊙ 시작, 종료

gdb[프로그램명] : 시작

q + ctrl+d : 종료

 

⊙ 브레이크 포인트

b * 0x08040000 : 특정 주소에 브레이크 포인터 설정

info b : 현재 브레이크 포인트 포인트 보기

cl : 브레이크 포인트 지우기

d : 모든 브레이크 포인트 지우기

 

⊙ 진행 명령어

r(run) : 프로그램 수행

k(kill) : 프로그램 수행 종료

s(step) : 현재 행 수행 후 정지, 함수 호출 시 함수 안으로 들어감.

c(continue) : 다음 브레이크 포인트까지 진행

finish : 현재 함수를 수행하고 빠져나감

return : 현재 함수를 수행하지 않고 빠져 나감

 

⊙ 기타

disas[함수명] : 특정함수의 어셈블리 코드 출력

disas [주소][주소] : 주소 사이의 어셈블리 코드 출력

'보안 > 포너블' 카테고리의 다른 글

포너블 Day6 pwnable.kr bof  (0) 2021.05.19
포너블 Day5 GDB 실행 과정  (0) 2021.05.12
포너블 Day4 collision 문제풀이  (0) 2021.05.05
포너블 Day3 리눅스 특수 권한  (0) 2021.05.05
[포너블 Day2] pwntools  (0) 2021.04.28

포너블 문제

 

ssh col@pwnable.kr -p2222

패스워드를 치고 문제에 들어왔다.

 

실행되지 않음

ls쳐서 플래그를 찾아야 되는걸 볼 수 있고

./flag를 치면 실행이 안된다.

 

20바이트 넘아야 된다.

aaaa를 썼을때 20바이트를 넘어야 되는걸 알수 있다.

 

20바이트는 되지만 정답이 아니다.

12345를 4번씩 써주면 20바이트는 되지만 wrong passcode가 나온다.

 

 

코드보기

1.  매개변수가 필요한 만큼 들어오지 않으면 usage 사용법을 출력하고 반환한다.

        if(argc<2){
                printf("usage : %s [passcode]\n", argv[0]);
                return 0;
        }

2. 들어온 매개변수가 20byte인지 확인한다. 20바이트가 아니면 반환한다.

        if(strlen(argv[1]) != 20){
                printf("passcode length should be 20 bytes\n");
                return 0;
        }

3. hashcode와 check_password를 비교한다.

참이면 flag출력하고 거짓이면 wrong password를 출력한다.

        if(hashcode == check_password( argv[1] )){
                system("/bin/cat flag");
                return 0;
        }
        else
                printf("wrong passcode.\n");

 


check_password함수 

unsigned long hashcode = 0x21DD09EC;
unsigned long check_password(const char* p){
        int* ip = (int*)p;
        int i;
        int res=0;
        for(i=0; i<5; i++){
                res += ip[i];
        }
        return res;
}

입력받은 문자열을 받아온다. 그후 int형 포인터 변수를 가리키고 for(i=0;i<5;i++) for문을 돌면서 4바이트씩 잘라서 res변수에 더한다.

 

res변수를 4바이트씩 끊어서 더한이유는 int형 포인터이기 때문이다.

 

매개변수 더한것이 0x21DD89EC랑 같아야한다.

 

계산(1)

 

어떤값 * 4 + 0x21DD09EC - 어떤값 * 4를 해본다.

어떤값은 임의의 값으로 1로 해보면 hex 0x01로 표기가 가능하다.

네자리수로 만들어야 되니 0x01010101로 쓸 수 있다.

 

어떤값 *4 = 0x01010101 * 4 = 0x04040404

 

 

0x21DD09EC - 0x04040404 = 1DD005E8

리틀엔디안을 사용하여 두개씩 잘라서 거꾸로 써줘야 한다.

E8 05 D9 1D

 

@정답

 

계산(2)

 

어떤값을 다른 값으로 해도 해결할 수 있는지 한번 해보겠다.

어떤값을 2로 바꾸어 보았다.

 

hex 0x02

0x02020202

 

0x02020202 * 4 = 0x08080808

 

0x21DD09EC -  0x08080808 = 19D5 01E4

 

실패... 다시 해봐고 업데이트 해야겠다..

'보안 > 포너블' 카테고리의 다른 글

포너블 Day5 GDB 실행 과정  (0) 2021.05.12
포너블 Day5 GDB설치, 명령어  (0) 2021.05.12
포너블 Day3 리눅스 특수 권한  (0) 2021.05.05
[포너블 Day2] pwntools  (0) 2021.04.28
[포너블 Day1]메모리 구조  (0) 2021.03.31

SetUID

◎ SetUID비트를 실행파일에 적용하면 프로그램을 실제 실행 중인 사용자 에서 프로그램의 소유자의 ID로 유효사용자(EUID)가 변경됨

 

프로세스 번호

- UNIX 시스템에서는 프로세스에 다섯가지 번호 부여

1. 프로세스 식별자 (PID)

2. 실제 사용자 ID (RUID=UID)

3. 유효 사용자 ID (EUID)

4. 실제 사용자 그룹 (RGID)

5. 유효 사용자 그룹 ID (EGID)

 

 사용 용도

계정 관리에 사용 : RUID, RGID

접근 권한 결정에 사용 : EUID, EGID

일반적으로 실제번호와 유효번호는 동일하다.

 

UID(=RUID) : 계정을 식별

EUID(Effecttive User ID) : 프로세스에 대한 권한을 결정

SUID(Saved User ID) : EUID 저장 복원

 

 

SetUID사용하는 이유

- 소유자가 root인 파일에 SetUID가 설정되어 있을때, 일반사용자가 그 file을 실행하게 되면 잠시 파일의 소유자인 root의 권한을 빌려오는 것이다.

- 매번 슈퍼 유저 root가 어떤 행위를 해주지 않아도 되고 일반 사용자에게 root권한을 주지 않아도 되기 때문에 SetUID를 적용한느 것이 시스템 운영면에서 효율적이다.

SetUID가 설정된 파일 실행시 특정 작업 수행을 위하여 일시적으로 파일 소유자의 권한을 얻게 된다.

 

SetUID 설정시 보안 취약점

- root 권한이 필요없는 프로그램의 소유주가 root로 되어 있고 SetUID가 설정된 경우 보안에 취약하다.

일반사용자로 접근하는 경우도 SetUID설정으로 실행 가능해지기때문이다. 

 

SetUID 설정방법

1) chomod root

chmod u+s 파일이름

2) chmod 4755 파일이름

chmod 4755 파일이름

 


 id 명령

 

id를 쓰고 id가 어디있는지 which id를 통해 알아본다.

id명령어의 소유자는 나인걸 알 수 있다.

 

sudo chowm root ./myid

sudo chmod 4755 ./myid

myid가 SetUID프로그램이 된걸 확인할 수 있다.

 

 

 

 

 

@cat 명령

 

위의 id와 같은 방법으로 cat도 해결해 주었다.

'보안 > 포너블' 카테고리의 다른 글

포너블 Day5 GDB 실행 과정  (0) 2021.05.12
포너블 Day5 GDB설치, 명령어  (0) 2021.05.12
포너블 Day4 collision 문제풀이  (0) 2021.05.05
[포너블 Day2] pwntools  (0) 2021.04.28
[포너블 Day1]메모리 구조  (0) 2021.03.31

+ Recent posts