passcode의 소스코드이다.
보기엔 간단해 보이지만 알고보면
scanf("%d", passcode1);
scanf("%d", passcode2);
처럼 양아치마냥 변수앞에 &를 안붙혀줬다. 변수 주소가 아니라 변수값이 인자로 넘어갈테니 당연하게도 segmentation Fault를 볼 수 있다.
그럼 이 주소를 덮을 수 있는지부터 생각 해 보자
기존에 입력을 받는 부분이 하나 있다 .
welcome()에 보면 scanf("%100s", name);이 보인다. 이걸로 덮을 수 있는지 확인해 보자.
해당스샷은 welcome에서 A를 무작위로 길게 넣어준 경우이다.
스택이나 레지스터에서 A가 여러번 들어간 모습을 볼 수 있다.
일단 덮어 쓸 수 있는것은 확인했다.
보아하니 passcode1은 ebp-0x10, passcode2는 ebp-0xc에 있는 것을 볼 수 있다.
welcome을 보면 lea edx,[ebp-0x70] 을 보아 ebp-0x70부터 100바이트만큼 받는것을 볼 수 있다.
0x70이 10진수로 112 0x10이 16, 0xc가 12라는 것을 보아, ebp - 0x10이 welcome() 의 name 의 마지막 4바이트가 남아있을 것을 예상할 수 있다.
그렇다면 0xc까지는 덮을 수 없다는 말이 된다.
passcode2의 주소를 덮어쓸 수 없으니 다른방법을 생각해보자.
보면 fflush(stdin)이 보인다.
이 명령어를 어떻게 수정해서 실행해보자.
GOT, PLT에 관한 개념은 RTL에서 사용했었다. 다시한번 언급하자면
프로세스에서 함수를 call할 때, 바로 그 주소로 가는게 아니라, 프로세스 내의 .plt table에 각 함수의 got값이 들어있고 이 주소로 가서 실행하게 된다.
마침 앞의 scanf의 dest주소도 덮어쓸 수 있다.
상황이 갖춰졌으니 주소를 알아보자.
평범한 상황이었으면 python파일을 짜서 ELF를 사용할테지만, 아쉽게도 pwnable.kr은 폴더에 쓰기도 안되고, 여러 제약이 있으니 한 줄 코드를 사용해야만 했다.
그래서 먼저 system 함수를 실행하는 instruction의 위치를 알아둬야한다.
보아하니 0x080485ea에 system함수를 호출하는것을 볼 수 있다.
그 위의 mov명령어는 system에 넘기는 인자를 의미한다.
보니 /bin/cat flag가 들어있는 것을 볼 수 있다.
인자없이 실행하는 것은 의미가 없으니 GOT를 0x080485e3으로 덮어써야 할것으로 보인다.
got를 보는것은 peda에서는 쉬운데, pwnable.kr에서는 got명령어가 실행되지 않아 직접 따야만 했다.
disassemble에서 fflush를 call하는 주소를 보면, 0x804a004라는 주소가 보인다.
이 주소를 열어보니 fflush@got.plt라고 한다. 0x804a004를 scanf로 덮어써 보자
페이로드는
(python -c 'print "A"*96 + "\x04\xa0\x04\x08"') |./passcode
또한, scanf에서 %d로 정수형으로 받기 때문에 0x080485e3를 10진수로 바꿔야 한다.
134514147이다.
이걸 페이로드 뒤에 붙혀주자
scanf에서 %100s로 받으므로, welcome()에서 앞쪽 100개를 들고가고
login의 첫번째 scanf에서 뒤쪽 정수값을 받을 것이다.
(python -c 'print "A"*96 + "\x04\xa0\x04\x08"' + "134514147") |./passcode
flag 득..
'pwnable > Toddler's Bottle' 카테고리의 다른 글
[Toddler's Bottle] input (0) | 2018.05.28 |
---|---|
[Toddler's Bottle] random (0) | 2018.05.21 |
[Toddler's Bottle] flag (0) | 2018.05.21 |
[Toddler's Bottle] bof (0) | 2018.05.19 |
[Toddler's Bottle] collision (0) | 2018.05.18 |